按照不知道是哪里开始的传统,学习语言的第一段可运行代码都会是一个“Hello World!”。于是我们也总是敲好这段代码后,感觉开始入门了,开始觉得精通了。可是对这个 ASP .NET 8 的 Web Application 开发学习过程,我们不如节省时间,跳过控制台应用直接从 Web 应用开始我们的旅程。
我们先从一个实用的应用开始一起学习,争取先让它成功地跑起来。

应用场景

几乎所有网站都会有一个用户反馈信息的页面,让用户可以提交评论,预约时间和提出疑问等等。这种应用需要实现下列几个重要功能:

  • 让用户提供联系方式
  • 让用户输入文字内容
  • 验证用户输入的内容
  • 提交完成后,显示总结和感谢信息

在这一章节里,我们会构建一个简单的 .NET 8 MVC Web Application 实现这些功能,并在最后适当调整和美化它的界面,让它更接近现实中生产版地样子。
我比较喜欢用 dotnet 命令行创建项目,快速简洁,一阵酸爽。

创建项目

打开PowerShell,输入:

dotnet new globaljson --sdk-version 8.0.400 --output UserFeed
dotnet new mvc --no-https --output UserFeed --framework net8.0
dotnet new sln -o UserFeed
dotnet sln UserFeed add UserFeed

我们用 dotnet 命令行设定 SDK 版本 8.0.400,接着创建新的 MVC(Model–view–controller) 项目,创建项目文件夹 UserFeed ,指定框架版本;创建新地解决方案,把项目 UserFeed 加入解决方案 UserFeed 中。
MVC(Model-view-controller) 是一种常用的软件设计模式,经常用于 Web Application 和 Web API 。简单说,就是把数据,用户界面独立开来,用流程控制逻辑把二者连接起来,最终完成软件目标。可以简化开发程序逻辑,加快开发速度,几乎是现在开发 World Wide Web 应用的标准。详情参见维基百科或者MDN

准备项目

打开项目(Visual Studio中打开UserFeed.sln文件或者用Visual Studio Code打开UserFeed文件夹),更改Properties文件夹中的launchSettings.json文件的内容为:

{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:5000",
      "sslPort": 0
    }
  },
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

我们把端口都改为5000,作为本地测试用。

打开 Controllers 文件夹中的 HomeController.cs 文件,把内容替换为 Listing 5-1。
Listing 5-1

using Microsoft.AspNetCore.Mvc;

namespace UserFeed.Controllers;

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

这是一个最简洁的应用入口,定义了一个 Action 方法,此方法返回缺省的 View。
修改 Views/Home 文件夹里的 Index.cshtml 文件内容为 Listing 5-2 ,显示欢迎信息。
Listing 5-2

@{
    ViewData["Title"] = "UserFeed";
}

<div class="text-center">
    <h1 class="display-6">欢迎留言,我们会尽快给您答复。非常感谢!</h1>
</div>

我们编译运行这个项目,在 PowerShell 中输入

dotnet run

或者我们想实时监视文件内容更改并运行项目,也可以输入

dotnet watch

当项目编译完成,Windows系统将打开缺省浏览器,显示类似如下页面:

Figure-5-1

Figure 5-1

我们保留运行dotnet watch的终端窗口,一旦有任何项目文件内容有改动,dotnet会自动编译运行应用,并刷新浏览器页面。

添加数据模型(Data Model)

数据模型是ASP.NET应用最重要的部分,而 Web Application 提供用户或管理者访问数据模型的途径,并和它们进行交互。
ASP.NET应用的数据模型类都存放在 Models 文件夹中。
Visual Studio: 鼠标右键点击 Models 文件夹,在右键菜单中选择 Add > Class(类),在弹出窗口给定文件名:FeedResponse.cs 再点击添加按钮。
VS Code: 鼠标右键点击左边文件夹树形列表中的 Models 文件夹,选择添加文件 FeedResponse.cs。
我们在这个文件中定义数据模型类,见Listing 5-3。
一般的,我们在一个文件中定义一个类
Listing 5-3

namespace UserFeed.Models;

public class FeedResponse
{
    public string? Name { get; set; }
    public string? Email { get; set; }
    public string? Message { get; set; }
}

String? 是表示可为Null的属性变量,因为用户可能没有在某些输入框中输入内容。这种情况很常见,我们后面会看到 Validation 验证数据显得多么重要。如果我们使用VS Code 的话,你会看到 dotnet watch 命令汇总终端给出警告,由于我们添加了一个新的文件,重新自动构建过程会中断:

watch : Do you want to restart your app - Yes (y) / No (n) / Always (a) / Never (v)?

键入 a ,表示我们希望它总是重新构建项目。

创建第二个 Action 和 View

我们的应用需要用户输入反馈信息,因此我们需要一个 Action 和一个 View 来接收和处理用户提交的内容。我们在 HomeController 中添加它们,见 Listing 5-4:
Listing 5-4

using Microsoft.AspNetCore.Mvc;

namespace UserFeed.Controllers;

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
    // 添加第二个Action方法
    public ViewResult ResponseForm() {
        return View();
    }
}

两个方法都返回 View() ,但是 .NET 的 Razor View 引擎会根据 Action 方法的名称寻找对应的 View 文件,就是说 Index() 方法会告诉 Razor 去寻找 Index.cshtml 文件,而 ResponseForm() 会对应 ResponseForm.cshtml。
Visual Studio: 鼠标右键点击 Views/Home 文件夹,选择 Add > New Item,选择 Razor View ,设定文件名:ResponseForm.cshtml,单击添加按钮。
VS Code: 鼠标右键点击 Views/Home 文件夹,选择添加文件:ResponseForm.cshtml。
替换文件内容为 Listing 5-5。
Listing 5-5

@{
    ViewData["Title"] = "Response Form";
}
<div>
    <h1>Response Form</h1>
</div>

目前这是一个静态网页;在浏览器地址栏输入http://localhost:5000/home/responseform,Razor 引擎会找到 ResponseForm.cshtml 文件,生成响应,如图 Figure 5-2 所示:

Figure 5-2

添加链接

我们在 Index 视图中添加一个到 ResponseForm 的链接,如 Listing 5-6 所示
Listing 5-6

@{
    ViewData["Title"] = "UserFeed";
}

<div class="text-center">
    <h1 class="display-6">欢迎留言,我们会尽快给您答复。非常感谢!</h1>
    @*添加链接*@
    <a asp-action="ResponseForm">用户留言</a>
</div>

我们注意到这里的链接是 asp-action="ResponseForm",表示由 ASP.NET 的 tag helper 生成的 url,而不是普通的 html 语言中的 href。这样我们可以充分利用 ASP.NET 带来的特性,兼容不同的 URL ,避免使用 hard-code 。

构建 Form 表格

现在我们要开始构建 Form 来处理用户的反馈,如 Listing 5-7 所示:
Listing 5-7 在ResponseForm 文件中创建一个 Form

<!-- add model reference -->
@model UserFeed.Models.FeedResponse 
@{
    ViewData["Title"] = "Response Form";
}
<div>
    <h1>Response Form</h1>
    <!-- begin build form -->
    <form asp-action="ResponseForm" method="post">
        <div class="form-group">
            <label asp-for="Name" class="control-label"></label>
            <input asp-for="Name" class="form-control" />
        </div>
        <div class="form-group">
            <label asp-for="Email" class="control-label"></label>
            <input asp-for="Email" class="form-control" />
        </div>
        <div class="form-group">
            <label asp-for="Message" class="control-label"></label>
            <textarea asp-for="Message" class="form-control"></textarea>
        </div>
        <div class="form-group">
            <input type="submit" value="Submit" class="btn btn-primary" />
        </div>
    </form>
    <!-- end build form -->
</div>

@model 表达式指定 FeedResponse 为这个视图的模型,注意到多个元素中的 asp-for 属性,这是一个很常见的 tag helper 属性,会根据模型对象构建出相应的 HTML 语句。比如,第一个 form-group 会被引擎生成为类似语句:

<label for="Name">Some Name</label>
<input type="text" id="Name" name="Name" value="" />

而对于 form 元素,引擎会生成类似:

<form method="post" action="/home/responseform">

从而可以被浏览器正确的解释执行。 我们会注意到 .NET 8 默认已经为应用添加了 BootStrap CSS framework 的,非常有助于快速开发。如果我们在浏览器里检查内容,可以在 <head></head> 标签里找到 bootstrap 的链接。
在应用主页点击“用户留言”链接,我们会看到如下页面 Figure 5-3:

Figure 5-3

接受 Form 数据

我们点击页面中的提交按钮,表格中的数据就会被传送给服务器。在逻辑上,我们可以理解为数据发送给了我们在 HomeController 中的 ResponseForm 方法,而这个方法的 return 语句就会重画(渲染)这个视图。在接下来开发开始以前,我们先花点时间了解一下 HTTP GET 请求和 HTTP POST 请求:
HTTP GET 请求是当用户点击某个链接时,浏览器向服务器请求读数据,服务器发送数据,浏览器呈现数据;而 HTTP POST 请求是浏览器发送数据给服务器,类似“写”数据到服务器,但是服务器不一定更改对应数据,所以写要加引号。
ASP .NET 可以给方法添加专门的特性(或属性),英文是 attribute ,以指定方法对应于 HTTP 请求。我们给原来的 ResponseForm 方法添加[HttpGet]属性,接着再添加一个[HttpPost]方法,如 Listing 5-8 所示:
Listing 5-8 添加一个新的 Post 方法

using Microsoft.AspNetCore.Mvc;
using UserFeed.Models; //添加引用 Models

namespace UserFeed.Controllers;

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [HttpGet] //Get 方法
    public ViewResult ResponseForm() {
        return View();
    }

    [HttpPost] //Post 方法
    public ViewResult ResponseForm(FeedResponse response) {
        // 处理提交的响应
        return View();
    }
}

我们的 Get 和 Post 方法的名字是一样的,所以加了属性限定以后,方法的函数签名是不同的,.NET 引擎会根据浏览器的行为自动寻找正确的方法执行。Post 方法需要把浏览器发送来的数据作为参数,而我们前面已经在 Razor 页面 ResponseForm .cshtml 里添加引用了数据模型类 FeedResponse ,所以在这个文件里要导入 using UserFeed.Models ,让 Post 方法可以使用这个 namespace 里的数据模型类 FeedResponse ,两者是要处理同一数据模型的。把两者连接在一起的机制,就是 .NET 极其重要的特性:数据模型绑定( model binding )。

理解数据模型绑定

数据模型绑定 model binding 可以理解为 .NET 把服务器与客户端(浏览器)交互的 HTTP 请求数据解释为键-值(key-value)对应的数据对,来呈现,更新或者填充应用里的数据模型类型。我们在服务器端就可以用 C# 来处理这些数据对象。
因为这是一个小应用,我们用内存数据集来存储接收到的 Form 数据,这些数据随着程序停止运行会丢失掉。而对于现实的生产应用,基本上我们会用数据库来存储数据。这样做是因为本来这只是一个演示嘛,数据丢失就重新来过也没有关系。 我们需要添加一个新的数据仓库类来存储数据。在 Models 文件夹中添加一个新文件 Repository.cs ,如 Listing 5-9 所示:
listing 4-9

namespace UserFeed.Models;

public static class Repository
{
    private static List<FeedResponse> responses = [];
    public static IEnumerable<FeedResponse> Responses => responses;
    public static void AddResponse(FeedResponse response) {
        Console.WriteLine($"Adding response{response}");
        responses.Add(response);
    }
}

这是一个静态类,所有方法都是静态方法。

保持响应数据

我们现在可以更新 Action 方法,把 HTTP Post 数据保存在静态对象中了,如 Listing 5-10 所示:
Listing 5-10 更新 HomeController.cs 文件

using Microsoft.AspNetCore.Mvc;
using UserFeed.Models;

namespace UserFeed.Controllers;

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
    [HttpGet]
    public ViewResult ResponseForm() {
        return View();
    }

    [HttpPost]
    public ViewResult ResponseForm(FeedResponse response) {
        Repository.AddResponse(response); // 存储提交响应
        return View("Thankyou", response);
    }
}

ResponseForm 的 HttpPost 方法返回一个 View ,名字是“Thankyou”,用来发送会以信息给用户,所以我们要在项目中添加一个 Thankyou 的 View。

添加 Thankyou 视图

在 Views/Home 文件里添加一个 Thankyou .cshtml 文件,内容如 Listing 5-11。
Listing 5-11 Thankyou.cshtml 文件

@model UserFeed.Models.FeedResponse
@{
    ViewData["Title"] = "Thank you";
}

<div>
    <h1>Thank you for your message, @Model?.Name! </h1> 
</div>
<div>
    Click <a asp-action="ResponseList">here</a> to see who had left a message.
</div>

我们打开表格页,输入信息,点击提交按钮后,服务端收到数据并把数据加入静态类 Repository 的 responses 列表中,并把数据模型的数据返回到 Thankyou 视图,我们就会再浏览器页面看到它,如图 Figure 5-4 所示:

Figure 5-4

现在需要添加一个新的端点(endpoint)指向 asp-action="ResponsesList" 表示的目标 URL :/Home/RespontseList 。我们再 HomeController .cs 添加一个新的 Action 方法,如 Listing 5-12 所示:
Listing 5-12

using Microsoft.AspNetCore.Mvc;
using UserFeed.Models;

namespace UserFeed.Controllers;

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
    [HttpGet]
    public ViewResult ResponseForm() {
        return View();
    }

    [HttpPost]
    public ViewResult ResponseForm(FeedResponse response) {
        Repository.AddResponse(response);
        return View("Thankyou", response);
    }

    // 添加新的方法
    public ViewResult ResponsesList() {
        return View(Repository.Responses);
    }
}

因为这个方法返回的 View 没有指定视图名称,我们需要为它新建一个名称和 Action 方法名称一样的视图,所以我们在 Views/Home 文件夹里添加一个文件名为 ResponsesList.cshtml的新文件,内容如 Listing 5-13:
Listing 5-13

@model IEnumerable<UserFeed.Models.FeedResponse>
@{
    ViewData["Title"] = "Responses List";
}

<div>
    <h1>接收反馈信息列表</h1>
    <ul>
        @foreach (var response in Model)
        {
            <li>
                <h4>名字:@response.Name</h4>
                <p>信息:@response.Message</p>
            </li>
        }
    </ul>
</div>

Razor 视图文件(*.cshtml)是 C# 和 HTML 的结合体。我们可以在这里用 C# 的 foreach 循环来遍历 ResponsesList 的所有项目,填充所有的 <li></li> 标签。浏览器页面呈现如图 Figure-5-5

Figure 5-5

目前页面样式比较丑陋,我们先保证数据能正确呈现,美化工作留到后面再做。因为对于用户数据,我们必须要添加验证机制,我们要让用户输入的数据符合我们的规范,给用户定规则,别让自己以后徒增烦恼。

添加验证

我们要给应用添加数据验证,以防止用户输入无效数据或者提交空白表格。我们通过给模型类添加属性给定验证规则。这些属性由 ASP .NET 的 System.ComponentModel.DataAnnotations 命名空间提供,我们把它们应用在 FeedResponse 类中, 如 Listing 5-14 所示。
Listing 5-14 添加验证属性

using System.ComponentModel.DataAnnotations;
namespace UserFeed.Models;

public class FeedResponse
{
    [Required(ErrorMessage = "请输入您的姓名")]
    public string? Name { get; set; }
    [Required(ErrorMessage = "请输入您的电子邮件地址")]
    [EmailAddress(ErrorMessage = "请输入有效的电子邮件地址")]
    public string? Email { get; set; }
    [Required(ErrorMessage = "请输入您的反馈信息")]
    public string? Message { get; set; }
}

ASP .NET 会检测到这些属性并在数据模型绑定的过程中用它们来验证用户数据。
给数据类添加验证属性后,还需要告诉 Action 方法,如果数据验证通过就按正常的流程来处理数据,否则需要进行其他处理。我们修改 HttpPost 方法如 Listing 5-15 所示:
Listing 5-15 添加条件判断

using Microsoft.AspNetCore.Mvc;
using UserFeed.Models;

namespace UserFeed.Controllers;

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
    [HttpGet]
    public ViewResult ResponseForm() {
        return View();
    }

    [HttpPost]
    public ViewResult ResponseForm(FeedResponse response) {
        //添加验证判断
        if(ModelState.IsValid) {
            Repository.AddResponse(response);
            return View("Thankyou", response);
        } else {
            return View();
        }
    }

    public ViewResult ResponsesList() {
        return View(Repository.Responses);
    }
}

HomeController 继承自 Controller 类,Controller 类提供一个属性 ModelState 来反映模型绑定的结果,如果数据满足验证属性的限定, ModelState.IsValid 返回 true , 方法就渲染和返回 Thankyou 视图,否则,就会产生验证错误,而我们要显示验证错误信息给用户,提示用户哪里出错,让用户修改并输入正确的数据。.NET 提供一个 tag helper 可以取得错误信息并呈现在客户端中。我们需要在视图中添加这个 tag helper,如 Listing 5-16 所示:
Listing 5-16 在 ResponseForm.cshtml 里添加验证总结

@model UserFeed.Models.FeedResponse
@{
    ViewData["Title"] = "Response Form";
}
<div>
    <h1>Response Form</h1>
    <form asp-action="ResponseForm" method="post">
        <!-- 添加验证总结 -->
        <div asp-validation-summary="All"></div>
        <!-- 添加验证总结 -->
        <div class="form-group">
            <label asp-for="Name" class="control-label"></label>
            <input asp-for="Name" class="form-control" />
        </div>
        <div class="form-group">
            <label asp-for="Email" class="control-label"></label>
            <input asp-for="Email" class="form-control" />
        </div>
        <div class="form-group">
            <label asp-for="Message" class="control-label"></label>
            <textarea asp-for="Message" class="form-control"></textarea>
        </div>
        <div class="form-group">
            <input type="submit" value="Submit" class="btn btn-primary" />
        </div>
    </form>
</div>

asp-validation-summary 属性会在验证出现错误时,被渲染并显示一个枚举变量 ValidationSummary 的值,我们用 All 指定要显示所有验证错误信息。我们这里试着把 Email 和 Message 留空,按提交按钮后,页面如 Figure 5-6 所示

Figure 5-6

每次提交后,数据验证如果不通过的话,输入正确的内容会保留下来,这也是数据模型绑定带来的好处。目前显示的错误信息字体的颜色是普通的字体颜色,我们想把这些字体改成红色,让错误警告更明显突出。我们可以为项目添加 Css 样式,这类文件一般都会存放在 wwwroot/css 文件夹里。我们在 wwwroot/css 文件夹里添加一个新文件 style.css ,内容如Listing 5-17 所示:
Listing 5-17 wwwroot/css 文件夹里的 style.css 文件

.field-validation-error {color: #f00;}
.field-validation-valid { display: none;}
.input-validation-error { border: 1px solid #f00; background-color: #fee; }
.validation-summary-errors { font-weight: bold; color: #f00;}
.validation-summary-valid { display: none;}

我们可以在浏览器里检查网页中错误信息的元素的类,就可以找到这些由 .NET 的 tag helper 产生的 HTML 的类名称。我们把 style.css 文件的链接引用放在 ResponseForm.cshtml 文件里:

...

<link rel="stylesheet" href="/css/style.css" />
<div>
    <h1>Response Form</h1>
    <form asp-action="ResponseForm" method="post">
...

如果我们也像上次一样,故意给下面两个输入框留空,点击提交;网页自动刷新后,数据验证文本字体将是红色粗体,而不能通过验证的输入框会变成粉红色背景并且带有红色边框,错误明显,方便易用。如图 Figure 5-7 所示:

表单数据验证
表单数据验证

Figure 5-7

现在所有功能都已经实现了,就是整体上的显示效果比较糟糕,看起来就是个半成品,既然 dotnet 给我们自动附带了 Bootstrap 框架,我们就用它来稍微美化一下我们的 Web Application ,尽量让它能接近成品。

美化应用

我们最先需要美化 Views/Shared/_Layout.cshtml,因为所有的页面都会被套上这个马甲,按如下 Listing 5-18 修改
Listing 5-18

<!DOCTYPE html>
...
    <title>@ViewData["Title"] - 用户信息回馈</title>
...
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">用户信息回馈</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">主页</a>
                        </li>
    <!-- 删除 privacy -->
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            © 2024  UserFeed  <!-- 删除 privacy -->
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Bootstrap 一下主页 Index.cshtml,见 Listing 5-19。
Listing 5-19

@{
    ViewData["Title"] = "UserFeed";
}

<div class="text-center">
    <h1 class="display-6">用户信息反馈</h1>
    <br />
    <h4>欢迎您留下宝贵的意见,我们会尽快答复您,非常感谢!</h4>
    <br />
    @* 添加链接 *@
    <a class="btn btn-primary" asp-action="ResponseForm">用户留言</a>
</div>

Bootstrap 表格页 ResponseForm.cshtml,见 Listing 5-20。
Listing 5-20

@model UserFeed.Models.FeedResponse
@{
    ViewData["Title"] = "Response Form";
}

<link rel="stylesheet" href="/css/style.css" />
<div class="container">
    <h1 class="text-center">反馈信息表</h1>
    <div class="row d-flex justify-content-center">
        <form class="m-2 p-3 col-md-6 col-sm-8" asp-action="ResponseForm" method="post">
            <div asp-validation-summary="All"></div>
            <div class="form-group my-2 col-md-6 col-sm-12">
                <label asp-for="Name" class="control-label">姓名</label>
                <input asp-for="Name" class="form-control" />
            </div>
            <div class="form-group my-2 col-md-6 col-sm-12">
                <label asp-for="Email" class="control-label">电子邮箱</label>
                <input asp-for="Email" class="form-control" />
            </div>
            <div class="form-group my-2">
                <label asp-for="Message" class="control-label">反馈信息</label>
                <textarea rows="8" asp-for="Message" class="form-control"></textarea>
            </div>
            <div class="form-group my-3 text-center">
                <input type="submit" value="提交" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

Bootstrap 感谢页 Thankyou.cshtml,见 Listing 5-21。
Listing 5-21

@model UserFeed.Models.FeedResponse
@{
    ViewData["Title"] = "Thank you";
}

<div class="text-center text-dark">
    <h1>@Model?.Name!  感谢您的反馈信息!</h1> 
</div>
<div class="text-center">
    <a asp-action="ResponsesList">点击此处</a>查看都有谁给我们反馈信息了。
</div>

Bootstrap 反馈用户列表页 ResponsesList.cshtml,见 Listing 5-22。
Listing 5-22

@model IEnumerable<UserFeed.Models.FeedResponse>
@{
    ViewData["Title"] = "Responses List";
}

<div class="m-2 p-2">
    <h3>接收反馈信息列表</h3>
    <ul class="list-group list-group-flush w-50">
        @foreach (var response in Model)
        {
            <li class="list-group-item">
                <h6>名字:@response.Name  电子邮箱:@response.Email</h6>
                <p>信息:@response.Message</p>
            </li>
        }
    </ul>
</div>

界面设计我不是很懂,请大家凑合看看。望见谅。

总结

这一章里,我们学习了用 ASP.NET 的 MVC 搭建一个最常见的表格提交应用,对数据模型绑定,类属性,方法属性和 tag helper 以及数据验证有了一定的了解。下一章,我们将继续学习 C# 语言经常在开发过程中用到的高级特性和常用的开发工具。

1 条回复

  1. This is simple and good

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注