ASP.NET Core 中的 MVC架构

MVC 架构

MVC架构把 App 按照逻辑分成三层:

  • Controllers,接收 http request,配合 model,通过http response 返回 view,尽量不做别的事
  • Models, 负责业务逻辑,App 的状态,以及数据处理
  • Views,呈现 UI,如果UI 较复杂,应该使用View 组件, ViewModel, 或者 view 模板

Controller

ASP.NET Core MVC 中的所有 Controller 都继承于 Controller 基类,而 ASP.NET Core WEB API 中的 Controller 都继承于 ControllerBase 基类,是因为Controller 基类支持 View。

Controller 可以返回三种类型的结果:

  • HTTP 状态码 或者 Redirect 结果
  • View 或者 格式化的结果(比如:Json(customer))
  • 与 Client 请求协商的结果

View

View 是使用 Razor 引擎标记的 HTML 模板页面。

Razor 引擎标记在服务端生成 HTML。

HMTL 中的 Razor 标记以 @ 开头,中间是{ ... }。比如:

html 复制代码
@{
    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。

csharp 复制代码
return View();

Action 也可以显示指定 View 名称:

csharp 复制代码
return View("Orders");

Action 显示指定 View 名称的时候,使用相对路径:

csharp 复制代码
return View("../Manage/Index");

或者:

csharp 复制代码
return View("./About");

Action 也可以不指定名称,但指定 Model:

csharp 复制代码
return View(Orders);

Action 也可以同时指定名称和 Model:

csharp 复制代码
return View("Orders", Orders);

向 View 传递数据可以使用强类型的 ViewModel 或者弱类型的 ViewData

ViewModel

也可以向 View 传一个 ViewModel,ViewModel是用于 View 的强类型 Model。

强类型意味着每个View 中的变量都在Model有对应的定义,使用 @model 指令:

html 复制代码
@model WebApplication1.ViewModels.Address

<h2>Contact</h2>
<address>
    @Model.Street<br>
    @Model.City, @Model.State @Model.PostalCode<br>
    <abbr title="Phone">P:</abbr> 425.555.0100
</address>

然后通过 return View(ViewModel) 传递给View:

csharp 复制代码
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

ViewData 是一个kv 结构的字典结构数据。

弱类型意味着即使 View 中找不到数据,也不会报错。

比如在 View 中使用的ViewData["Greeting"]和ViewData["Address"]:

html 复制代码
@{
    // 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:

csharp 复制代码
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 属性定义:

csharp 复制代码
public class HomeController : Controller
{
    [ViewData]
    public string Title { get; set; }

    public IActionResult About()
    {
        Title = "About Us";
        ViewData["Message"] = "Your application description page.";

        return View();
    }
}

Partial View

当需要拆分大型 View 或者复用小型View时,可以使用 Partial View功能。

Partial View 中没有 @page 指令。

Partial View 不运行 _ViewStart.cshtml。

Partial View 的名称通常以下划线 _ 开头。

Action 返回 Partial View:

csharp 复制代码
public IActionResult OnGetPartial() =>
    Partial("_AuthorPartialRP");

在 View 中通过 Tag Helper 使用 Partial View:

html 复制代码
<partial name="_PartialName" />

Partial View 的搜索路径

MVC 中:

  1. /Areas//Views/
  2. /Areas//Views/Shared
  3. /Views/Shared
  4. /Pages/Shared

Razer Page 中:

  1. 当前页面文件夹
  2. 当前页面的上一级文件夹
  3. /Shared
  4. /Pages/Shared
  5. /Views/Shared

异步 HTML Helper

使用HTML Helper时,一般使用 PartialAsync。

PartialAsync 返回 Task 类型的 IHtmlContent。

html 复制代码
@await Html.PartialAsync("_PartialName")

Layout

Web App 一般都有布局,类似这样:

默认的布局文件名放在 Views/Shared/_Layout.cshtml 。

Layout 中一般会调用:

html 复制代码
@RenderBody()

Layout 中可以引用多个部分,每个部分通过RenderSection替换:

html 复制代码
<script type="text/javascript" src="~/scripts/global.js"></script>

@RenderSection("Scripts", required: false)

路由 Routing

路由的作用是把客户端的 http 请求 url 映射到Controllers的具体类的具体 Action 上。

路由语法可以参考 https://blog.csdn.net/cuit/article/details/132587534

比如:

初始时时基于约定的路由:

csharp 复制代码
routes.MapRoute(name: "Default", template: "{controller=Home}/{action=Index}/{id?}");

Controller中基于属性的路由:

csharp 复制代码
[Route("api/[controller]")]
public class ProductsController : Controller
{
    [HttpGet("{id}")]
    public IActionResult GetProduct(int id)
    {
    }
}

Model 绑定

Model 绑定功能把客户端的请求数据(表彰数据,路由数据,请求字符串,HTTP header)转换成 controller可以接收的对象。这样,controller 就不用分析请求数据,直接把请求数据作为 Action 的入参。

csharp 复制代码
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null) { ... }

Model 验证

使用Model 绑定功能后,可以在客户端发送请求之前就验证请求数据,以及在 Action 处理之前验证数据。

csharp 复制代码
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的代码:

csharp 复制代码
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 指令注入:

html 复制代码
@inject SomeService ServiceName

<!DOCTYPE html>
<html lang="en">
<head>
    <title>@ServiceName.GetTitle</title>
</head>
<body>
    <h1>@ServiceName.GetTitle</h1>
</body>
</html>

筛选器 Filters

Filters 用于预处理或者后处理 pipeline 中的请求,比如异常处理,缓存,Authorization,日志。

比如:

Areas

Areas 用于分组功能。

MVC 架构中,Model, Controller, 和 View 代码放在不同的物理文件夹中。

而在大型 App 中,还需要把每个Controller/Model/View模块按功能放在不同的子分组中。

强类型的 View

Controllers 可以向 View 返回一个强类型 Model 的 View。

比如这个类型为IEnumerable的 View。

csharp 复制代码
@model IEnumerable<Product>
<ul>
    @foreach (Product p in Model)
    {
        <li>@p.Name</li>
    }
</ul>

Tag Helpers

Tag Helpers 用于 server 端生成 HTML。

Tag Helpers 可以自定义 HTML元素或者修改现有 HTML 元素。

Tag Helpers 绑定到 HTML元素的属性上。

Tag Helpers 有原生支持和第三方开发的。

比如:LinkTagHelper 可以用于创建指向AccountsController.Login 的链接。

html 复制代码
<p>
    Thank you for confirming your email.
    Please <a asp-controller="Account" asp-action="Login">Click here to Log in</a>.
</p>

比如:EnvironmentTagHelper 可以用于根据环境使用不同的 HTML:

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>

内置的Tag Helpers

  • asp-controller 和asp-action,生成 URL,比如:
html 复制代码
<a asp-controller="Speaker"
   asp-action="Evaluations">Speaker Evaluations</a>

生成:

html 复制代码
<a href="/Speaker/Evaluations">Speaker Evaluations</a>
  • asp-route,asp-all-route-data,asp-route-{value},asp-area,匹配路由
  • asp-fragment,生成 html 锚点
  • asp-protocol,指定 http 协议,比如 https
  • asp-host,指定 url 的主机名
  • asp-page,生成 hrel 的超链接
  • cache,distributed-cache,缓存数据
  • environment,根据环境使用不同的 HTML
  • form,生成表单
    • formaction,提前表单
    • input,
    • label
    • select
    • textarea
    • asp-validation-for
    • asp-validation-summary
  • img,加强img标签。
  • Link 类
    • href
    • asp-fallback-href
  • partial,partial view
  • script
相关推荐
冰块的旅行1 小时前
magic-api使用
后端
用户89535603282201 小时前
Goroutine + Channel 高效在哪?一文吃透 Go 并发底层 G-M-P 调度与实现
后端·go
鸽芷咕1 小时前
静态住宅 IP 实战测评:手把手教你高效获取全球前沿资讯
后端
西召1 小时前
Spring Kafka 动态消费实现案例
java·后端·kafka
lomocode1 小时前
前端传了个 null,后端直接炸了——防御性编程原来这么重要!
后端·ai编程
镜花水月linyi1 小时前
ThreadLocal 深度解析(上)
java·后端
镜花水月linyi1 小时前
ThreadLocal 深度解析(下)
java·后端
JavaEdge.1 小时前
Spring数据源配置
java·后端·spring
铭毅天下1 小时前
Spring Boot + Easy-ES 3.0 + Easyearch 实战:从 CRUD 到“避坑”指南
java·spring boot·后端·spring·elasticsearch
李慕婉学姐1 小时前
【开题答辩过程】以《基于Springboot的惠美乡村助农系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·spring boot·后端