用户:小朱/沙盒/ASP.NET MVC

维基百科,自由的百科全书
ASP.NET MVC
开发者Microsoft
编程语言.NET 编程语言,例如C#VB.NET
类型ASP.NETMVC
许可协议Apache License 2.0
网站www.asp.net/mvc/

ASP.NET MVC 是微软发展的 Web 应用程序开发框架之一,以ASP.NET为核心发展,属于 One ASP.NET 技术架构的成员之一。

虽然与 Web Forms 开发模型相同的核心,但它是以 MVC (Model/View/Controller) 的设计模式概念为基础,将 Model、View 与 Controller 三者分开设计,其核心理念之一为关注点分离 (Separation of Concerns)。由于使用的是完全不同的设计概念,因此 Web Form 和 MVC 应用程序得以共存,也可以择一使用。ASP.NET MVC 的主程式被封装于 System.Web.Mvc.dll 内。

ASP.NET MVC 早期以 MS-PL (Microsoft Public License) 授权规范 [3] 开放源代码,自2012年3月起改为 Apache License 2.0 规范,后续的版本仍持续以 Open Source 方式释出源代码。

ASP.NET MVC 也是下一代 .NET 平台 .NET Core 的钦定 Web 应用程序开发框架。

程式设计模型

ASP.NET MVC 采用的 MVC 遵循 Model/View/Controller 分离的架构,依照关注点分离的概念,以及习惯取代配置 (Convention over Configuration) 的理念,ASP.NET MVC 将三个不同的部件分离到三个不同的资料夹内,Model 配置于 Models 资料夹、Controller 配置于 Controllers 资料夹、View 则配置于 Views 资料夹等,在 Visual Studio 内的 ASP.NET MVC 专案范本也确实的依这个原则产生,但这也是很容易被外界误解的地方,以为一定要照规则走才能正常作业,然而事实上 Model 和 View 和 Controller 不但可以分开配置,甚至还可以切割成不同专案。

ASP.NET MVC 的生命周期 [4] 源自 HTTP 的要求 (Request),当 ASP.NET MVC 设置于 IIS 上的 ASP.NET Routing Module (位于 System.Web.Routing.dll 内的 UrlRoutingModule 类别) 拦截到 HTTP 的要求时,会解析 HTTP 的 URL,取得与路由表 (Routing Table) 对应的 URL 参数,找出 Controller 的位置,并使用 Controller Activator 初始化 Controller 物件,并将 HTTP 的要求资讯转送到 Controller 内;Controller 内在处理完成之后,会回传一个继承自 ActionResult 的结果物件,ActionResult 本身会将所需要的讯息与结果输出到 HTTP 回应资料流,并回传到使用者的浏览器 (或 HTTP 用户端),完成一整个的 HTTP 动作。

模型 (Model)

在 ASP.NET MVC,资料模型并不是强制必要的项目,依照习惯取代配置原则,ASP.NET MVC 会认为资料的模型会放在 Models 资料夹内,但这并不是强制要求,所以资料模型可以放在任何专案,只要 Controller 能够找到并存取即可。在 MVC 应用程序的 Model 多半会使用强型别的 DTOPOCO 来组合运用,因此大多数的 ASP.NET MVC 范例会使用 ADO.NET Entity Framework 作为例子,但这并不代表 ASP.NET MVC 一定得用 Entity Framework 或是 ORM-based 的解决方案 (如 NHibernate),若是需要或是维持相容性,MVC 还是能使用传统的 ADO.NET DataTable 或 DataSet,然而依现代应用程序的架构,使用 DTO/POCO 等强型别的资料方案会较适合。

虽然 Model 在 ASP.NET MVC 内是被动的角色,但 ASP.NET MVC 还是提供了一些支援来简化处理与传递 Model 的作业,例如 Model Binding 技术,能将传入 Controller 的资料简化为使用 Model 参数即可;Model Validation 则是可以在 Controller 内对 Model 的检验进行处理,可使用程式码或是用特征项 (Attribute) 的方式来处理。

模型验证 (Model Validation)

模型验证功能 [5] 是由 .NET Framework 3.5 SP1 开始新增的 System.ComponentModel.DataAnnotations 命名空间所提供的资料标记为基础所实作的功能,开发人员可透过加入简单的资料验证特征,就可以在 Controller 中使用 ModelState.IsValid 来确认模型是否有效 (即符合资料标记的要求)。

例如下列程式码,每个属性都套用了资料标记的特征。

public class Movie
{
    public int ID { get; set; }

    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime ReleaseDate { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")]
    [Required]
    [StringLength(30)]
    public string Genre { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")]
    [StringLength(5)]
    public string Rating { get; set; }
}

控制器 (Controller)

ASP.NET MVC 的 Controller 物件负责处理 HTTP 的要求,并将结果以 ActionResult 的物件回传 (不过这也不是强制的,若 MVC 核心发现方法是 void 时,预设会回传 EmptyResult[6]),再由 MVC 核心接手呼叫 ActionResult 内的实作来取得 HTTP 回传的内容。所有应用程序内的 Controller 物件都要继承自 Controller 基础类别,以获取 Controller 所需的功能。

方法

开发人员依照需要于 Controller 内配置一个或多个方法以处理 HTTP 讯息,依预设,Controller 内的 public 方法都可以由 HTTP URL 的路由转入 (在不改变预设路由的情况下),若是不想对外公开 (内部用的方法) 时,可以在方法上加上 [NonAction] 特征项,以封锁方法不被路由取得。每个方法预设会由 HTTP GET 取用,若是需要由其他的 HTTP 动词唤起,可在方法上加入 [HttpPost]/[HttpPut]/[HttpDelete] 或是 [ActionVerb] 来设定允许由哪个 HTTP 动词唤起。

方法的参数

Controller 内的方法可以使用参数,参数的来源有两种:

  1. 由 URL 提供,这个功能由 ASP.NET Routing 实作,只要应用程序的路由表有注册 URL 的参数 (可以是 URL 路径内的片段,也可以是 Query String)。
  2. 由 HTTP 的讯息提供,当 Controller 的方法宣告了 [HttpPost][HttpPut] 特征项时,Controller 的 Model Binding 会将讯息的相对字段系结到 Model 内。

基本上 Controller 内方法的参数应使用允许 NULL 的资料型态,若是数值型别则应使用 Nullable<T> 型别的参数,string 因为本来就可以接受 NULL 所以无需使用 Nullable<T>,否则当 Model Binding 找不到指定参数的资料时,会掷回例外。若不使用参数接值,ASP.NET MVC 也提供了 Controller.Request 属性来取得 HTTP 的要求,这表示开发人员可以自行操作 Request.QueryStringRequest.Form 取得 HTTP 的讯息资料。

方法回传值

Controller 内的方法一般都需要回传 ActionResult 或其衍生类别的物件,ASP.NET MVC 提供了下列内建的 ActionResult 实作品供开发人员选择。

  • ViewResult物件,这个物件内装载了IView界面的资讯,以及IViewEngine的资讯,实际产生输出资料的会是 IViewEngine,以及其指示的 View 物件。
  • PartialViewResult物件,与ViewResult相似,但它回传的是"部分展示",即使用者控件的View。
  • ContentResult物件,装载由使用者自订的 Content-Type 以及资料。
  • EmptyResult物件,表示不回传任何东西。
  • HttpUnauthorizedReuslt物件,表示动作没有被授权(即 HTTP 401)的错误讯息。
  • JavaScriptResult物件,表示回传的是JavaScript指令码。
  • JsonResult物件,表示回传的是JSON资料。
  • FileResult物件,表示回传的是一个档案资料。
  • RedirectResult物件,表示回传的是一个重导向 (HTTP Redirect) 指令。
  • RedirectToRouteResult物件,与 RedirectResult 类似,但是它是重导向给一个 Route 的路径。
  • RedirectToActionResult物件,与 RedirectResult 类似,但是它是重导向到指定的 Controller 的动作。

若需要自行设计自己的 ActionResult,可继承 ActionResult 类别并覆写其 ExecuteResult() 方法,以产生自订的 HTTP 回应内容 [7]

在 ASP.NET MVC 6 中,ActionResult 类别由 IActionResult 界面取代,以提供更强的界面合约机制 [8]

动作过滤器

动作过滤器 (Action Filter) [9]是 ASP.NET MVC 提供扩充 HTTP 处理流程能力的机制。ASP.NET MVC 提供了预设的几种 Action Filter 给开发人员使用:

  1. AuthorizeAttribute: 控制授权的动作。
  2. HandleErrorAttribute: 控制处理错误的动作。
  3. OutputCacheAttribute: 控制执行动作的结果输出快取的动作。
  4. RequireHttpsAttribute: 控制是否强制使用 HTTPS (SSL) 的动作。

若是需要,开发人员利用实作 ActionFilterAttribute 类别来实作自订的动作过滤器,ActionFilterAttribute 提供数种方法可覆写:

  • OnAuthorization: 当动作需要授权时触发。
  • OnException: 当动作发生例外时触发。
  • OnActionExecuting: 在动作执行前呼叫。
  • OnActionExecuted: 在动作执行后,Controller 回传 ActionResult 前呼叫。
  • OnResultExecuting: 在 Controller 回传 ActionResult 后,但在产生结果之前呼叫。
  • OnResultExecuted: 在产生结果后呼叫。

其中 OnActionExecutingOnResultExecuting 所提供的事件参数包含了 Cancel 属性,开发人员可决定是否要取消动作;OnActionExecutedOnResultExecuted 的事件参数则包含了 Exception 属性与 ExceptionHandled 属性,Exception 属性内含执行动作与产生结果时产生的 Exception (没有的话为 NULL),若是动作过滤器内可处理掉 Exception,则可设定 ExceptionHandled = true,这样就不会中断动作的执行。

检视 (View)

在 ASP.NET MVC 中,检视功能通常是指由 View Engine (检视引擎) 所产生的 HTML 内容。

ASP.NET MVC 在早期 (v1.0-2.0) 时使用的是 ASPX-based View Engine,其副档名与 ASP.NET Web Form 相同,并且支援 .aspx (检视)、.ascx (部分检视) 以及 .master (主版页面) 三种,其标记语法也相容于 ASP.NET Web Form 的 <% ... %> 语法,也因为采用了 Web Form 的语法 (和以前的 ASP 语法很相像),导致 ASP.NET MVC 初期容易被误解为 ASP 复辟。

下列指令为 ASPX-based View Engine 的例子:

<ul>
    <%foreach (var item in Products)
      {  %>
             <% if (item.IsInStock)
                { %>
                    <p><%=item.ProductName%> is in stock</p>
             <% }
                else
                { %>
                    <p><%=item.ProductName%> is not in stock</p>
             <% } %>
    <%} %>
</ul>

在 ASP.NET MVC v3.0 开始,ASP.NET MVC 团队提出了新的 View Engine,称为 Razor-based View Engine [10],其检视内使用的程式指令为 Razor,是微软特别为 ASP.NET MVC 而开发,其副档名为 .cshtml (C#) 或是 .vbhtml (VB),但 URL 内不必包含 .cshtml 或 .vbhtml,表示不需要副档名,其程式码内使用的语法也更简洁。

下列指令为 Razor-based View Engine 的例子:

<ul>
    @foreach (var item in Products)
    {
               @if(item.IsinStock)
               {   
                   @item.ProductName is in stock
               } else {
                   @item.ProductName is in stock
               } 
    }
</ul>

但不论是 ASPX 或是 Razor,ASP.NET MVC 的检视让开发人员能使用指令弹性的在 HTML 内自由添加资料或是其他的 HTML 内容,让 MVC 检视可调整的自由度更大。

检视功能虽然是 MVC 的其中一环,但在 ASP.NET MVC 中不一定是必要项 (若方法回传的不是 ViewResult 物件时就不会驱动 View Engine 的功能),应用程序可以不回传以 HTML 为主的内容,此时回传的资料会取决于 ActionResult 的 ExecuteResult() 的输出内容。

HTML Helpers

为辅助检视产生特定的 HTML,例如针对 Routing 路由表的超链接、表单的 HTML 或是其他需要的 HTML 内容,ASP.NET MVC 设计了一组 HTML Helper [11],以 Html. 为开头,并同时提供针对弱型别 Model 与强型别 Model 的实作 (方法中有 For 字样的),例如:

<h2><%= Html.Encode(ViewData["Message"]) %></h2>
<br /><br />
<% using(Html.BeginForm("HandleForm", "Home")) %>
<% { %>
    Enter your name: <%= Html.TextBox("name") %>
    <br /><br />
    Select your favorite color:<br />
    <%= Html.RadioButton("favColor", "Blue", true) %> Blue <br />
    <%= Html.RadioButton("favColor", "Purple", false)%> Purple <br />
    <%= Html.RadioButton("favColor", "Red", false)%> Red <br />
    <%= Html.RadioButton("favColor", "Orange", false)%> Orange <br />
    <%= Html.RadioButton("favColor", "Yellow", false)%> Yellow <br />
    <%= Html.RadioButton("favColor", "Brown", false)%> Brown <br />
    <%= Html.RadioButton("favColor", "Green", false)%> Green 
    <br /><br />
    <%= Html.CheckBox("bookType") %> I read more fiction than non-fiction.<br />
    <br /><br />
    My favorite pet: <%= Html.DropDownList("pets") %>
    <br /><br />
    <input type="submit" value="Submit" />
<% } %>

部分检视

部分检视 (Partial View) [12]允许开发人员产生网页内容的一部分,在 ASPX View Engine 中使用 .ascx 为副档名,而 Razor View Engine 则一样采用 .cshtml/.vbhtml 作为副档名,在 View 程式中呼叫 Html.RenderPartial() 或是 Html.Partial() 即可产生部分检视的内容,如下例:

@Html.Partial("~/Views/Shared/_Product.cshtml", product);

版本历程

版本历程
日期 版本
2007/12/10 ASP.NET MVC CTP
2009/03/13 ASP.NET MVC 1.0[13]
2009/12/16 ASP.NET MVC 2 RC[14]
2010/02/04 ASP.NET MVC 2 RC 2[15]
2010/03/10 ASP.NET MVC 2[16]
2010/10/06 ASP.NET MVC 3 Beta[17]
2010/11/09 ASP.NET MVC 3 RC[17]
2010/12/10 ASP.NET MVC 3 RC 2[18]
2011/01/13 ASP.NET MVC 3[19]
2011/09/20 ASP.NET MVC 4 Developer Preview[20]
2012/02/15 ASP.NET MVC 4 Beta[21]
2012/03/31 ASP.NET MVC 4 RC[22]
2012/08/15 ASP.NET MVC 4[23]
2013/05/30 ASP.NET MVC 4 4.0.30506.0 [24]
2013/06/26 ASP.NET MVC 5 Preview [25]
2013/08/23 ASP.NET MVC 5 RC 1[26]
2013/10/17 ASP.NET MVC 5[26]
2014/01/17 ASP.NET MVC 5.1[26]
2014/02/10 ASP.NET MVC 5.1.1[26]
2014/04/04 ASP.NET MVC 5.1.2[26]
2014/06/22 ASP.NET MVC 5.1.3[26]
2014/07/01 ASP.NET MVC 5.2.0[26]
2014/08/28 ASP.NET MVC 5.2.2[26]
2015/02/09 ASP.NET MVC 5.2.3[26]
2015/11/07 ASP.NET MVC 6.0.0-beta1[27]
2015/11/18 ASP.NET MVC 6.0.0-rc1[27]

与 Web Form 模型的比较

ASP.NET MVC 虽然与 Web Forms 是系出同门的 ASP.NET 开发技术,但两者是完全不同的走向,因此也经常被拿来做比较。

基本上,Web Form 和 MVC 所擅长的领域是不同的:

  • Web Forms 擅长的是快速开发,以控件为主的事件驱动开发方式,熟悉以事件驱动为基础开发的开发人员能以较短时间快速进入 Web 应用程序的开发领域。
  • MVC 擅长的是架构导向的开发,以 HTTP 处理流程为主,若是熟悉 ASP 以及 HTTP 处理流程的开发人员 (例如 PHP, JSP, Perl, node.js, Python 等) 能快速的学会并应用。

下表为 Web Forms 与 MVC 的比较[28]

ASP.NET Web Forms ASP.NET MVC
以网页或控件的生命周期为主,采用 Code-Behind 方式撰写程式码,每个网页都是它自己的控制器。 以标准的 HTTP 流程 (Request/Response) 为主,以 Controller 来处理要求与回应,程式码写在 Controller 内,由 URL 路由决定使用的控制器。
没有关注点分离的概念,网页和程式码是紧密的结合。 有关注点分离的概念,Controller 和 View 并没有直接关联,Controller 内的方法可依需求来决定使用的 View。
程式码较难依职责切割,因此较难以施行单元测试以及自动测试。 可测试性是 MVC 的关键功能,因此能很容易的导入单元测试与自动测试 (或是测试驱动开发)
为了保存网页状态而导入 ViewState,使得网页容易变得笨重,但提供与 Windows Forms 相似的作法。 本身是以无状态方式提供,因此没有 ViewState,但状态保存要由开发人员处理。
需经由完整的网页生命周期 (Page Life Cycle)。 无网页生命周期,由要求周期 (Request Cycle) 替代。
为了要做到与 Windows Forms 类似的作法,Web Forms 提供了相当多的控件,它基本上会自动产生相应的 HTML, CSS, JavaScript,所以只需要最少的相关知识即可。 需要有较完整的 HTML, CSS, JavaScript 的知识,否则无法随心所欲的操作 View。
对 HTML 没有太多的控制能力,或是要花较多额外的工作处理。 具有完整的 HTML 控制能力。
能在有限的知识之下实行快速开发。 以 HTTP 流程步骤为主,生产力取决于开发人员的能力。
适合小型开发团队与小规模的应用程序。 适合职责分离的团队,并且适合中大型的应用程序。

知名应用

在此列举一些使用 ASP.NET MVC 开发的知名网站:

参考

  1. ^ ASP.NET MVC 5.2.3, Web Pages 3.2.3 and Web API 5.2.3 Release
  2. ^ Announcing ASP.NET 5 Release Candidate 1
  3. ^ MS-PL 授权规范
  4. ^ ASP.NET MVC Lifecycle
  5. ^ Adding Validation
  6. ^ Extreme ASP.NET - The Life And Times of an ASP.NET MVC Controller
  7. ^ How to Create Custom ActionResult Method in ASP.Net MVC4
  8. ^ Controllers, Actions, and Action Results
  9. ^ Filtering in ASP.NET MVC
  10. ^ Introduction to ASP.NET Web Programming Using the Razor Syntax
  11. ^ 使用 HTML Helper 在 ASP.NET MVC 呈现表单
  12. ^ Partial View in ASP.NET MVC 4
  13. ^ Download ASP.NET MVC 1.0 from Official Microsoft Download Center. Microsoft. [17 January 2015]. 
  14. ^ Phil Haack. ASP.NET MVC 2 RC Released. [17 January 2015]. 
  15. ^ Phil Haack. ASP.NET MVC 2 RC 2 Released. [17 January 2015]. 
  16. ^ Download ASP.NET MVC 2 RTM from Official Microsoft Download Center. Microsoft. [17 January 2015]. 
  17. ^ 17.0 17.1 ASP.NET MVC 3. The Official Microsoft ASP.NET Site. [17 January 2015]. 
  18. ^ ScottGu's Blog - Announcing ASP.NET MVC 3 (Release Candidate 2). [17 January 2015]. 
  19. ^ Download ASP.NET MVC 3 RTM from Official Microsoft Download Center. Microsoft. [17 January 2015]. 
  20. ^ ASP.NET. CodePlex. [17 January 2015]. 
  21. ^ ASP.NET MVC 4. The Official Microsoft ASP.NET Site. [17 January 2015]. 
  22. ^ MSDN Blogs. Microsoft. [17 January 2015]. 
  23. ^ MSDN Blogs. Microsoft. [17 January 2015]. 
  24. ^ ASP.NET and Web Tools 2012.2 Release Notes. The Official Microsoft ASP.NET Site. [17 January 2015]. 
  25. ^ Microsoft ASP.NET Team. ASP.NET and Web Tools for Visual Studio 2013 Release Notes. The Official Microsoft ASP.NET Site. [17 January 2015]. 
  26. ^ 26.0 26.1 26.2 26.3 26.4 26.5 26.6 26.7 26.8 NuGet Gallery - Microsoft ASP.NET MVC 5.2.2. [17 January 2015]. 
  27. ^ 27.0 27.1 aspnet/Mvc. GitHub. [2015-10-16]. 
  28. ^ Difference betweeen ASP.NET WebForms and ASP.NET MVC
  29. ^ Stack Overflow: The Architecture - 2016 Edition