翻译: 张海龙(jiechen)
校对: 高嵩

ASP.NET Core MVC 是使用模型-视图-控制器(Model-View-Controller)设计模式构建网页应用与 API 的丰富的框架。

什么是 MVC 模式?

模型-视图-控制器(MVC)架构模式将一个应用区分为三部分主要组件:模型、视图、与控制器。这种模式有助实现 关注分离 。使用这种模式,用户请求被路由到控制器,控制器负责与模型(Model)协作以执行用户操作和/或返回请求结果。控制器(Controller)选择视图(View),展示给用户,而给视图提供其所需要的任何模型(Model)。

下面的图表展示了这三个主要组件以及它们间的相互引用:

这个职责示意图帮你掌控你的应用的复杂程度,因为其更容易编码、调试、与测试一些(模型、视图、控制器)有单一功能的模块 (进一步了解 单一职责原则 )。存在两者或者此三者之间的广泛依赖是非常难更新、测试、调试代码的。例如,用户界面逻辑与业务逻辑相比倾向于变化更频繁。如果表现代码与业务逻辑混杂在一个对象内,在你每次改变用户界面的时候都需要修改一个包含业务逻辑的对象。这也就更容易引入错误,并使得你在每次做一个很小的用户界面改动后都要进行完整的业务逻辑测试。

视图与控制器都依赖于模型。尽管如此,模型并不依赖于视图,也不依赖于控制器。这是分离的一大优势。这样分离允许不依赖于视觉表现创建并测试模型。

模型(Model)职责

MVC 应用中的模型代表了应用的状态和业务逻辑或其可以展现的一些操作。业务逻辑应该封装在模型,连同应用持久化状态实现逻辑。强类型视图一般使用特别设计的视图模型(ViewModel)类型,它包含了视图显示需要的数据;控制器将创建并从模型填充这些视图模型。

有许多种方法组织 MVC 架构形式的应用中的模型。了解更多关于 不同类型的模型

视图(View)职责

视图负责在用户界面呈现内容。它们使用 Razor 视图引擎 在 HTML 标记中嵌入 .NET 代码。视图中应仅包含少量的逻辑,而这些逻辑应该是与呈现内容相关的。如果你发现需要在视图文件中完成大量的逻辑任务,以便从复杂的模型展示数据,请考虑使用 视图组件 视图模型、或视图模板来简化视图。

控制器(Controller)职责

控制器是承载用户交互、模型运转、并最终选择视图进行渲染的组件。在 MVC 应用中,视图只显示信息;控制器处理并对用户输入和交互做出响应。在 MVC 模式,控制器是最初的入口,负责选择同哪一个模型类型协作和选择哪一个视图用来呈现(就如其名:它控制应用对所给的请求如何做出响应)。

控制器不应该有太多职责而过于复杂。 为避免控制器逻辑过于复杂,请使用 单一职责原则 将业务逻辑从控制器移到领域模型。

如果你发现你的控制器方法频繁执行相同类型的方法,你可以依照 不要让自己重复原则 将这些通用方法移入 过滤器 .

什么是 ASP.NET Core MVC

ASP.NET Core MVC 框架是一个为使用 ASP.NET Core 优化的轻量级、开源、高度可测试的表现框架。

ASP.NET Core MVC 提供了一种基于模式的、使用干净的关注分离的方式构建动态网站。它使你能对标签完全控制,支持友好的测试驱动开发(TDD)开发方式并且使用最新的 Web 标准。

ASP.NET Core MVC 包括以下特点:

  • 网络应用程序接口
  • Razor视图引擎
  • 强类型视图
  • 标签辅助类
  • ASP.NET Core MVC 是建立在 ASP.NET Core 路由 上的,一项强大的 URL 映射组件,助你建立拥有可理解的、可搜索的 URL 的应用。这使得你可以定义你的应用的 URL 命名形式,使得它对搜索引擎优化(SEO)和链接生成中运行良好,而不用关心你的 WEB 服务器上的文件如何组织。你可以使用方便的路由模板语法定义你的路由,路由模板语法支持路由值约束、默认值和可选值。

    基于约束的路由 允许你全局定义你的应用支持的 URL 格式,及这些格式如何各自在给定的控制器中映射到指定的操作(Action)方法。 当接收到传入请求,路由引擎转换 URL 且匹配它至一个定义的 URL 格式模板,然后调用关联的控制器的操作方法。

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

    特性路由(Attribute routing) 允许你以在控制器和方法使用添加特性的方式指定路由信息来定义你的应用的路由。这意味着你的路由定义紧邻它们所关联的控制器和方法。

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

    模型(Model)绑定

    ASP.NET Core MVC 模型绑定转换客户端请求数据(从值、路由数据、请求字符参数、HTTP 标头)为控制器可以处理的对象。所以,你的控制器逻辑不需要做识别传入请求数据的工作;使得参数数据传入到操作方法简单化。

      public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null) { ... }
    

    模型(Model)验证

    ASP.NET Core MVC 支持 校验,通过为你的模型对象添加数据批注校验特性装饰。校验特性在客户端数值传到服务器之前被检查,同时在控制器方法被调用之前也会检查。

      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; }
    

    一个控制器方法:

      public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
          if (ModelState.IsValid)
            // work with the model
          // If we got this far, something failed, redisplay form
          return View(model);
    

    框架在客户端和服务端都将处理请求数据校验。在模型上指定的验证逻辑被添加到渲染后的视图中作为隐藏脚本,且利用 jQuery Validation在浏览器中被强制执行。

    ASP.NET Core 内置了对 依赖注入 (DI)的支持。在 ASP.NET Core MVC 中 控制器 能通过它们的构造函数请求所需的服务,允许它们遵循 显式依赖项原则

    你的应用也可以使用 视图文件中的依赖注入,使用 @inject 命令:

      @inject SomeService ServiceName
      <!DOCTYPE html>
        <title>@ServiceName.GetTitle</title>
      </head>
        <h1>@ServiceName.GetTitle</h1>
      </body>
      </html>
    

    过滤器(Filters)

    过滤器帮助开发者封装横切关注点,如异常处理或身份验证。过滤器允许运行为操作方法自定义的前期的和请求过程中的逻辑,也可以被配置为在给定请求的执行管道的特定时刻执行。过滤器可以作为特性被应用到控制器或方法(也可以全局运行)。框架包含了几项过滤器(比如 Authorize )。

        [Authorize]
        public class AccountController : Controller
    

    区域(Areas)

    Areas提供了一种将庞大的 ASP.NET Core MVC 网站应用分解的方法。区域是应用中一项有效的MVC结构。在 MVC 项目中,逻辑组件如 Model、控制器及视图放在不同的文件夹,MVC 使用命名规范来在这些组件间建立关系。对庞大的应用,将应用分解为单独的高级功能区域是非常有益的。例如,一个电子商务应用拥有多个业务单元,比如结算、账单、与搜索等。这些单元中的每一项都有它们各自的逻辑组件视图、控制器和模型。

    网络应用程序接口(Web APIs)

    除了是一个强大的创建网站的平台,ASP.NET Core MVC 对 Web APIs 也具有强有力的支持。你可以创建服务,连接到广泛的客户端,包括各种浏览器和移动设备。

    框架内置支持格式化数据如 JSON 或 XML ,使其具备了对 HTTP 内容协商的支持。编写自定义格式以支持你的自有格式。

    使用链接生成可以启用对超媒体的支持。简单地启用对跨域资源共享 (CORS)的支持,可使得你的 Web APIs 能在多个应用间共享。

    可测试性(Testablility)

    框架接口和依赖注入的使用,使其适合进行单元测试,且框架包含的功能(如 TestHost 和 Entity Framework 内存提供程序)使得集成测试也是非常快捷和方便的。了解更多关于测试控制器逻辑

    Razor 视图引擎

    ASP.NET Core MVC 视图使用Razor 视图引擎渲染视图。 Razor 是一种紧凑的、表达能力好且流畅的模板标记语言,用来使用嵌入的 C# 代码定义视图。Razor 被用来在服务器动态生成 Web 内容。你可以清晰地将服务端代码和客户端代码跟内容混合在一起。

    @for (int i = 0; i < 5; i++) { <li>List item @i</li>

    使用 Razor 视图引擎你可以定义布局模板,局部视图及可替换的区块。

    强类型视图

    MVC 中的 Razor 视图可以强类型于你的模型。控制器可以传递强类型模型到视图,使你的视图支持类型检查和智能提示。

    例如,下面的视图定义了 IEnumerable<Product> 类型的模型:

      @model IEnumerable<Product>
          @foreach (Product p in Model)
              <li>@p.Name</li>
    

    标签辅助类(Tag Helper)

    Tag Helpers使得服务端代码可以在 Razor 文件中参与创建和渲染 HTML 元素。你可以使用 tag helper 定义自己的标签(比如 <environment>)或更改已知标签的行为(如 <label>)。 Tag Helper 依据元素名称和属性绑定到指定元素。它们为服务端渲染带来便利的同时保留了 HTML 编辑体验。

    有很多内置的 Tag Helper 应对常用任务,比如创建表单、链接、加载资源等,并且在公共的 GitHub 仓库或作为 NuGet 包,还有更多可用的。Tag Helper 是用 C# 创作的,它们通过元素名、属性名或父标签定位 HTML 元素。例如,内置的 LinkTagHelper 可被用来创建一个链接指向到 AccountsControllerLogin 方法:

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

    EnvironmentTagHelper 可以用来在运行时环境包含不同的脚本到你的视图(例如:原始的或压缩的),例如 Development, Staring, 或 Production:

      <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.min.js"
                  asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
                  asp-fallback-test="window.jQuery">
          </script>
      </environment>
    

    Tag Helper 提供友好的 HTML 开发体验和创建 HTML 与 Razor 标记时的丰富的智能提示。大多数内置的 Tag Helper 指向存在的 HTML 元素并且为元素提供服务端属性。

    View Components允许你打包渲染逻辑并在应用中重用它。它们与局部视图类似,但具有相关的逻辑。

    由于水平有限,错漏之处在所难免,欢迎大家批评指正,不胜感激,我们将及时修正。
    dotNet Core Studying Group:436035237