MVC架构把 App 按照逻辑分成三层:
ASP.NET Core MVC 中的所有 Controller 都继承于 Controller 基类,而 ASP.NET Core WEB API 中的 Controller 都继承于 ControllerBase 基类,是因为Controller 基类支持 View。
Controller 可以返回三种类型的结果:
View 是使用 Razor 引擎标记的 HTML 模板页面。
Razor 引擎标记在服务端生成 HTML。
HMTL 中的 Razor 标记以 @ 开头,中间是{ … }。比如:
@{
ViewData["Title"] = "About";
}
具体语法参考:
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-8.0#razor-syntax
ASP.NET Core MVC 中的一个 View 是一个 .cshtml 代码文件。

一般一个 Controller 对应一个 View 文件夹,一个Action 可能对应一个 View。
View 的文件夹结构一般是:Views/[ControllerName] 。
多个 Controller 共享的 View 放在 Views/Shared 中。
View 的名称一般与 Action 的名称相同。
如果Action返回的 View 不指定具体View名称,则返回与 Action 方法相同的 View。
此时 ASP.NET Core 会从Views/[ControllerName]和Views/Shared 中查找同名 View。
return View();
Action 也可以显示指定 View 名称:
return View("Orders");
Action 显示指定 View 名称的时候,使用相对路径:
return View("../Manage/Index");
或者:
return View("./About");
Action 也可以不指定名称,但指定 Model:
return View(Orders);
Action 也可以同时指定名称和 Model:
return View("Orders", Orders);
向 View 传递数据可以使用强类型的 ViewModel 或者弱类型的 ViewData
也可以向 View 传一个 ViewModel,ViewModel是用于 View 的强类型 Model。
强类型意味着每个View 中的变量都在Model有对应的定义,使用 @model 指令:
@model WebApplication1.ViewModels.Address
<h2>Contacth2>
<address>
@Model.Street<br>
@Model.City, @Model.State @Model.PostalCode<br>
<abbr title="Phone">P:abbr> 425.555.0100
address>
然后通过 return View(ViewModel) 传递给View:
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
var viewModel = new Address()
{
Name = "Microsoft",
Street = "One Microsoft Way",
City = "Redmond",
State = "WA",
PostalCode = "98052-6399"
};
return View(viewModel);
}
ViewModel 类一般就是一个 POCO 类,即只有属性,没有方法的数据类。
ViewData 是一个kv 结构的字典结构数据。
弱类型意味着即使 View 中找不到数据,也不会报错。
比如在 View 中使用的ViewData[“Greeting”]和ViewData[“Address”]:
@{
// Since Address isn't a string, it requires a cast.
var address = ViewData["Address"] as Address;
}
@ViewData["Greeting"] World!
<address>
@address.Name<br>
@address.Street<br>
@address.City, @address.State @address.PostalCode
address>
通过 Action 中定义后通过return View() 传给 View:
public IActionResult SomeAction()
{
ViewData["Greeting"] = "Hello";
ViewData["Address"] = new Address()
{
Name = "Steve",
Street = "123 Main St",
City = "Hudson",
State = "OH",
PostalCode = "44236"
};
return View();
}
也可以通过ViewData 属性定义:
public class HomeController : Controller
{
[ViewData]
public string Title { get; set; }
public IActionResult About()
{
Title = "About Us";
ViewData["Message"] = "Your application description page.";
return View();
}
}
当需要拆分大型 View 或者复用小型View时,可以使用 Partial View功能。
Partial View 中没有 @page 指令。
Partial View 不运行 _ViewStart.cshtml。
Partial View 的名称通常以下划线 _ 开头。
Action 返回 Partial View:
public IActionResult OnGetPartial() =>
Partial("_AuthorPartialRP");
在 View 中通过 Tag Helper 使用 Partial View:
<partial name="_PartialName" />
MVC 中:
Razer Page 中:
使用HTML Helper时,一般使用 PartialAsync。
PartialAsync 返回 Task 类型的 IHtmlContent。
@await Html.PartialAsync("_PartialName")
Web App 一般都有布局,类似这样:

默认的布局文件名放在 Views/Shared/_Layout.cshtml 。
Layout 中一般会调用:
@RenderBody()
Layout 中可以引用多个部分,每个部分通过RenderSection替换:
<script type="text/javascript" src="~/scripts/global.js">script>
@RenderSection("Scripts", required: false)
路由的作用是把客户端的 http 请求 url 映射到Controllers的具体类的具体 Action 上。
路由语法可以参考 https://blog.csdn.net/cuit/article/details/132587534
比如:
初始时时基于约定的路由:
routes.MapRoute(name: "Default", template: "{controller=Home}/{action=Index}/{id?}");
Controller中基于属性的路由:
[Route("api/[controller]")]
public class ProductsController : Controller
{
[HttpGet("{id}")]
public IActionResult GetProduct(int id)
{
}
}
Model 绑定功能把客户端的请求数据(表彰数据,路由数据,请求字符串,HTTP header)转换成 controller可以接收的对象。这样,controller 就不用分析请求数据,直接把请求数据作为 Action 的入参。
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null) { ... }
使用Model 绑定功能后,可以在客户端发送请求之前就验证请求数据,以及在 Action 处理之前验证数据。
using System.ComponentModel.DataAnnotations;
public class LoginViewModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
Action的代码:
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
if (ModelState.IsValid)
{
// work with the model
}
// At this point, something failed, redisplay form
return View(model);
}
.NET 会同时在客户端和服务端进行 Model 验证。
可以在 Controller 的构造函数中注入依赖类,也可以在 View 中使用 @inject 指令注入:
@inject SomeService ServiceName
DOCTYPE html>
<html lang="en">
<head>
<title>@ServiceName.GetTitletitle>
head>
<body>
<h1>@ServiceName.GetTitleh1>
body>
html>
Filters 用于预处理或者后处理 pipeline 中的请求,比如异常处理,缓存,Authorization,日志。
比如:

Areas 用于分组功能。
MVC 架构中,Model, Controller, 和 View 代码放在不同的物理文件夹中。
而在大型 App 中,还需要把每个Controller/Model/View模块按功能放在不同的子分组中。
Controllers 可以向 View 返回一个强类型 Model 的 View。
比如这个类型为IEnumerable的 View。
@model IEnumerable<Product>
<ul>
@foreach (Product p in Model)
{
<li>@p.Name</li>
}
</ul>
Tag Helpers 用于 server 端生成 HTML。
Tag Helpers 可以自定义 HTML元素或者修改现有 HTML 元素。
Tag Helpers 绑定到 HTML元素的属性上。
Tag Helpers 有原生支持和第三方开发的。
比如:LinkTagHelper 可以用于创建指向AccountsController.Login 的链接。
<p>
Thank you for confirming your email.
Please <a asp-controller="Account" asp-action="Login">Click here to Log ina>.
p>
比如:EnvironmentTagHelper 可以用于根据环境使用不同的 HTML:
<environment names="Development">
<script src="~/lib/jquery/dist/jquery.js">script>
environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.js"
asp-fallback-src="~/lib/jquery/dist/jquery.js"
asp-fallback-test="window.jQuery">
script>
environment>
<a asp-controller="Speaker"
asp-action="Evaluations">Speaker Evaluationsa>
生成:
<a href="/Speaker/Evaluations">Speaker Evaluationsa>