ASP.NET MVC Framework

ASP.NET MVC Framework是微软在ASP.NET中所添加的一组类别库,这组类别库可以使用Model-View-Controller设计模式来开发ASP.NET的应用程序。它与现有的ASP.NET应用程序并没有冲突,所以两者是可以并行的。ASP.NET MVC Framework被包装在System.Web.Mvc.dll中,并利用ASP.NET Routing来支持动作流以及URL Rewriting的能力,让它可以更贴近Web的发展以及Web 2.0的特性。对于多数有ASP开发经验的开发人员来说看起来比较不陌生,但对于没有接触过像ASP、PHPJSPPerl这些Web开发工具的开发人员来说,相对的不容易入门。ASP.NET MVC 的第一个版本于2009年3月17日发布RTM版本,最新的ASP.NET MVC 5.2则是于2014年12月24日正式发行。

ASP.NET MVC Framework
开发者Microsoft
最终版本
  • 3.3.0 (2023年10月24日;稳定版本)[1]
  • 8.0.2 (2024年2月13日;稳定版本)[2]
源代码库
编程语言.NET 编程语言,例如C#VB.NET
由…取代ASP.NET Core
类型Web应用程序MVC
许可协议Apache License 2.0
网站www.asp.net/mvc/

微软于 ASP.NET Core 中提出下一代的 MVC 框架,称为 ASP.NET Core MVC

原理

ASP.NET MVC是遵循软件模式的Model-View-Controller来发展,其中Model指的是数据或是业务逻辑组件,View是呈现给用户看的信息,而Controller则是接取来自用户的指令与数据,并将Model与View做集成的控制器,当服务器接到对ASP.NET MVC应用程序的要求时,服务器(IIS)会先使用UrlRoutingModule(ASP.NET Routing的 HTTP 模块),由它来解析是否有包含ASP.NET MVC应用程序的URL,若有,则会产生一个MvcRouteHandler对象,这个对象会装载运行的必要信息,并且会调用包含在URL中的Controller的Execute方法来运行工作[3]

Controller对象是基于IController接口的规则所定义,提供针对HTTP要求做回应的一个运行工具,在ASP.NET MVC中已实作一个缺省的类别 Controller,提供了必要的基础功能,另外也发展了一个 Controller 工厂,称为 Controller Factory,以IControllerFactory接口定义,亦提供了DefaultControllerFactory,开发人员可以利用基本的类别以及利用它们来衍生自己的 Controller 或 Controller Factory 来实作自己的控制器逻辑功能。

Model对象则是为ASP.NET MVC提供数据,不过它没有基础类别,而是使用.NET Framework一般性的数据结构或是现在的ADO.NET数据对象,像是List、Dictionary、DataTable、DataReader与DataSet等等,当然也可以是自己开发的商业对象,这些数据会通过ASP.NET MVC的ModelBinder工具类别来与Controller集成,ModelBinder本身是支持泛型(Generic)的,因为各种类型的数据它都可以使用。在ASP.NET MVC中提供了一个DefaultModelBinder对象,可支持大多数的.NET Framework数据类型,以及数组和已实作像是IList、IDictionary以及ICollection等接口的对象[4]

Model会在Controller运行动作时,作为一个ActionResult对象方式传回给MvcHandler对象,而这个对象即会指定要显示的View对象,像是下列代码所示:

using System.Linq;
using System.Web.Mvc;
using System.Web;
using System;

    // GET: /Person/
    public ActionResult Index()
    {
        return View(people);
    }

    // GET: /Person/Details/5
    public ActionResult Details(Person person)
    {
        return View(person);
    }

    // GET: /Person/Create
    public ActionResult Create()
    {
        return View();
    } 

    // POST: /Person/Create
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Person person)
    {
        if (!ModelState.IsValid)
        {
            return View("Create", person);
        }

        people.Add(person);

        return RedirectToAction("Index");
    }


Public Class HomeController
    Inherits System.Web.Mvc.Controller
    
    'GET: /Person/
    Function Index() As ActionResult
        Return View(people)
    End Function

    'GET: /Person/Details/5
    Function Details(Person person) As ActionResult
        Return View(person)
    End Function
    
    'GET: /Person/Create
    Function Create() As ActionResult
        Return View()
    End Function

    'POST: /Person/Create
    <AcceptVerbs(HttpVerbs.Post)>
    Function Contact() As ActionResult
        If ModelState.IsValid Then
            Return View("Create", person)
        Else
            people.Add(person)
            Return RedirectToAction("Index")
        End If
    End Function

End Class

View对象以IViewIViewDataContainer等接口为主,并且以ASP.NET的各式前端接口为主要输出工具,基于MVC的View弹性化设计考量,以往在ASP.NET Web Form的代码与HTML分离模式将不再存在,而是将代码与HTML混合的方式设计,让开发人员可以更精确的对View进行控制,而目前 ASP.NET MVC 支持的 View 有下列几种[5]

  • .aspx网页,由ViewPage来支持。
  • .ascx用户控制项,由ViewUserControl来支持。
  • .master主版页面,由ViewMasterPage来支持。

每个 View 对象都会内含一个泛型的参数,用来装载要呈现的数据(即Model),然后使用类似下面的方式来呈现数据:

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html >
<head runat="server">
    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
</head>

<body>
    <div class="page">

        <div id="header">
            <div id="title">
                <h1>My MVC Application</h1>
            </div>

            <div id="logindisplay">
                <% Html.RenderPartial("LogOnUserControl"); %>
            </div> 

            <div id="menucontainer">

                <ul id="menu">              
                    <li><%= Html.ActionLink("Home", "Index", "Home")%></li>
                    <li><%= Html.ActionLink("About", "About", "Home")%></li>
                </ul>

            </div>
        </div>

        <div id="main">
            <asp:ContentPlaceHolder ID="MainContent" runat="server" />

            <div id="footer">
            </div>
        </div>
    </div>
</body>
</html>

技术

在ASP.NET MVC架构中,除了Controller、Model与View三个主要部份以外,还包含了许多技术以让这三层得以集成并交互运作。

Controller

Controller在ASP.NET MVC应用程序中是负责中控的角色,也是来自用户端HTTP要求的处理内核,因此有许多处理与转向HTTP要求的辅助技术在Controller层次都会使用到。

ASP.NET 路由技术

用来过滤用户端要求的URL,并借由定义好的路由表(route table)将要求导向至正确的MVC Controller,并调用Controller中的Execute方法运行,而Execute方法会将HTTP动作以及实际运行的指令交给正确的函数来运行。而通常一个MVC应用程序的URL都会是类似这样的URL格式:

http://127.0.0.1/ControllerName/ActionName/ActionParameters

而MvcRouteHandler会拆解URL,找出目标的Controller,并且将ActionName以及ActionParameters传给Controller中负责的函数(以ActionName来指定)。例如下列的URL会传递给BlogController的GetList方法:

http://127.0.0.1/Blog/GetList

动作与方法直接集成

ASP.NET MVC利用了中介数据的技术,直接将方法对应到指定的 HTTP 动词 (GET/POST/PUT/DELETE/HEAD等),MvcHandler会判断要求的类别,并将它交给URL中指定的方法来处理。目前MVC Framework可用下列的方式指定(均包含在 HttpVerbs 枚举类型中):

  • HttpVerbs.Get
  • HttpVerbs.Post
  • HttpVerbs.Delete
  • HttpVerbs.Put
  • HttpVerbs.Head

将数据模型与展示层直接包装

ViewPageViewMasterPageViewUserControl等展示对象都支持泛型对象,可以直接装载Model数据传递至前端输出,可简化处理Model与View之间集成的动作,只要一个参数就可以将数据传给View:

public ActionResult GetList()
{
    return View(BlogDataModel);
}


    Function GetList() As ActionResult
        Return View(BlogDataModel)
    End Function

Model

在 ASP.NET MVC 中,Model 相对不设限,可以使用内置的数据结构以及自订的数据类别,也可以是一个商业对象,因此 Model 的弹性相当大,除了前述的数据结构外,微软新发展的一些数据访问方式也可以应用在 Model 中,像是ADO.NET Entity FrameworkLINQ to SQL等技术。

另外,MVC在伺服端数据验证中,提供了ViewDataDictionary类别,这个类别中有一个ModelState属性,内含了ModelStateDictionary类别,开发人员可以利用这个类别来控制数据验证的结果,而View中输出验证消息的部份会和此类别有关联,例如下列的程序:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Person person)
{
    if (person.Name.Trim().Length == 0)
    {
        ModelState.AddModelError("Name", "Name is required.");
    }
    if (person.Age < 1 || person.Age > 200)
    {
        ModelState.AddModelError("Age", "Age must be within range 1 to 200.");
    }
    if ((person.Zipcode.Trim().Length > 0) && (!Regex.IsMatch(person.Zipcode, @"^\d{5}$|^\d{5}-\d{4}$")))
    {
        ModelState.AddModelError("Zipcode", "Zipcode is invalid.");
    }
    if (!Regex.IsMatch(person.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
    {
        ModelState.AddModelError("Phone", "Phone number is invalid.");
    }
    if (!Regex.IsMatch(person.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
    {
        ModelState.AddModelError("Email", "Email format is invalid.");
    }
    if (!ModelState.IsValid)
    {
        return View("Create", person);
    }

    people.Add(person);

    return RedirectToAction("Index");
}

在 ASP.NET MVC 2.0 中,添加了一个可以直接让 MVC Framework 针对数据字段进行验证控制的模型,称为 Model Validation,它融合了在 .NET Framework 3.5 SP1 发表的 ASP.NET Dynamic Data Framework 中 Data Annotations (数据记号) 的特性,让开发人员可以只利用标记的方式来运行验证,或是利用自订的代码来扩充数据记号的验证行为。

using System.ComponentModel.DataAnnotations;  
namespace MvcDA {
    [MetadataType(typeof(ProductMD))]
    public partial class Product {
        public class ProductMD {
            [StringLength(50),Required]
            public object Name { get; set; }
            [StringLength(15)]
            public object Color { get; set; }
            [Range(0, 9999)]
            public object Weight { get; set; }
          //  public object NoSuchProperty { get; set; }
        }
    }
}

View

由于View是直接呈现给用户,因此与用户交互的部份都要由此层处理,包含数据的输出以及以用户端操作为主的回应(例如脚本)等。

HTML 工具类别

HTML工具类别在View中是很重要的输出工具,它内置了辅助产生HTML标签的工具方法,多数的HTML语法都可以利用它来产生,包含像链接(<a>)、表单(<form>)以及表单控制项等等。HTML工具是以HtmlHelper类别为内核,并配合System.Web.Mvc.Html命名空间的方法,以延伸方法(Extension Method)的方式,让产生HTML的程序就有如调用方法般简单[6]

<h2>Index</h2>

<table>
    <tr>
        <th></th>
        <th>
            Id
        </th>
        <th>
            Name
        </th>
    </tr>

<% foreach (var person in Model) { %>

    <tr>
        <td>
            <%= Html.ActionLink("Details", "Details", person )%>
        </td>
        <td>
            <%= Html.Encode(person.Id) %>
        </td>
        <td>
            <%= Html.Encode(person.Name) %>
        </td>
    </tr>

<% } %>

</table>

<p>
    <%= Html.ActionLink("Create New", "Create") %>
</p>

数据验证

View的HTML工具可以配合Model处理数据验证的结果,在ASP.NET中常用的ValidationSummary在这里也支持,而且MVC的架构让验证信息的输出也更加弹性[7]

<h2>Create</h2>

<%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>

<% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="Name">Name:</label>
            <%= Html.TextBox("Name") %> Required
            <%= Html.ValidationMessage("Name", "*") %>
        </p>
        <p>
            <label for="Age">Age:</label>
            <%= Html.TextBox("Age") %> Required
            <%= Html.ValidationMessage("Age", "*") %>
        </p>
        <p>
            <label for="Street">Street:</label>
            <%= Html.TextBox("Street") %>
            <%= Html.ValidationMessage("Street", "*") %>
        </p>
        <p>
            <label for="City">City:</label>
            <%= Html.TextBox("City") %>
            <%= Html.ValidationMessage("City", "*") %>
        </p>
        <p>
            <label for="State">State:</label>
            <%= Html.TextBox("State") %>
            <%= Html.ValidationMessage("State", "*") %>
        </p>
        <p>
            <label for="Zipcode">Zipcode:</label>
            <%= Html.TextBox("Zipcode") %>
            <%= Html.ValidationMessage("Zipcode", "*") %>
        </p>
        <p>
            <label for="Phone">Phone:</label>
            <%= Html.TextBox("Phone") %> Required
            <%= Html.ValidationMessage("Phone", "*") %>
        </p>
        <p>
            <label for="Email">Email:</label>
            <%= Html.TextBox("Email") %> Required
            <%= Html.ValidationMessage("Email", "*") %>
        </p>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

<% } %>

<div>
    <%=Html.ActionLink("Back to List", "Index") %>
</div>

不同类型的输出

每一个Controller中负责回应的方法,都会回传一个ActionResult对象的信息,ActionResult是一个运行结果对象的封装体,当MvcHandler运行完指令接到ActionResult时,就会依照它的内容来输出数据。目前MVC Framework支持的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 的路径。

通过多类型的ActionResult,开发人员可以自由决定要回传的数据的类型与格式。

应用

目前微软有一个Oxite项目,是使用ASP.NET MVC Framework所开发的博客引擎,而这个项目已经被微软的部份应用平台所采用,像是MIX Online、PDC 2009、MIX Video等官方网站都采用它来开发[8]。另外,stackoverflow.com以及codeplex.com这两个网站也是采用ASP.NET MVC Framework。

版本历程

版本历史
日期版本注释
2007-12-10ASP.NET MVC Framework以CTP方式发布
2008-03-05ASP.NET MVC Preview 2已发布
2008-05-01ASP.NET MVC Preview 3已发布
2008-07-16ASP.NET MVC Preview 4已发布[9]
2008-08-28ASP.NET MVC Preview 5已发布[10]
2008-10-16ASP.NET MVC Beta已发布[11]
2009-01-27ASP.NET MVC RC已发布[12]
2009-03-03ASP.NET MVC RC 2已发布[13]
2009-03-17ASP.NET MVC 1.0已发布[14]
2009-07-31ASP.NET MVC 2.0 Preview 1已发布[15]
2009-11-17ASP.NET MVC 2.0 Beta已发布[16]
2010-03-11ASP.NET MVC 2.0 RTM已发布[17]
2010-10-06ASP.NET MVC 3.0 Beta持续更新中[18]
2010-11-08ASP.NET MVC 3.0 RC已发布[19]
2011-01-13ASP.NET MVC 3.0 RTM已发布[20]
2011-09-20ASP.NET MVC 4.0 Developer Preview已发布[21]
2012-02-15ASP.NET MVC 4.0 Beta随着Microsoft .NET Framework 4.5 RC发布[22]
2012-05-31ASP.NET MVC 4.0 RC[23]
2012-08-15ASP.NET MVC 4.0[23]
2013-10-17ASP.NET MVC 5.0[24]
2014-01-17ASP.NET MVC 5.1[25]
2014-2-10ASP.NET MVC 5.1.1
2014-4-4ASP.NET MVC 5.1.2
2014-6-22ASP.NET MVC 5.1.3
2014-7-1ASP.NET MVC 5.2[26]
2014-8-28ASP.NET MVC 5.2.2
2015-2-9ASP.NET MVC 5.2.3
2018-2-12ASP.NET MVC 5.2.4[27]
2018-5-2ASP.NET MVC 5.2.5[28]
2018-5-11ASP.NET MVC 5.2.6
2018-11-29ASP.NET MVC 5.2.7
2022-4-12ASP.NET MVC 5.2.8 (最新版)

授权

ASP.NET MVC Framework虽然是ASP.NET的一部份,不过它的原代码是通过Microsoft Public License (MS-PL)的授权模式公开,因此在MS-PL授权的范围内,任何人是可以去查看与修改它的原代码的。[29]

ASP.NET MVC Razor Engine

微软在2010年7月2日由Scott Guthrie发表新的MVC绘制引擎 (Render Engine):Razor Engine[30],它已内置于 ASP.NET MVC 3.0 中发布,它具有下列功能:

  1. 更轻量化且直觉的语法,减少在 View 中输出数据时使用的语法,让 View 的指令更加简洁,例如使用 "@" + 变量名称 的方式,就可以输出程序中的变量,不必再用 <% %> 来设置。如果程序有多行,可以使用 @{ } 的方式来设置。
  2. 容易学习。
  3. 可兼容于现在的编程语言 (ex: C#)。
  4. 通过 Visual Studio,可享有 Intellisense 能力。
  5. 可混用 HTML 与编程语言指令。
  6. 可用各种不同的文本编辑器编辑。
  7. 具有单元测试的能力。

参考数据

  1. . 2023年10月24日 [2023年11月18日].
  2. . 2024年2月13日 [2024年2月18日].
  3. . [2009-08-31]. (原始内容存档于2009-08-21).
  4. . [2009-08-31]. (原始内容存档于2009-08-15).
  5. . [2009-08-31]. (原始内容存档于2009-09-08).
  6. . [2009-08-31]. (原始内容存档于2009-08-15).
  7. . [2009-08-31]. (原始内容存档于2009-08-19).
  8. . [2009-08-31]. (原始内容存档于2009-08-15).
  9. ASP.NET MVC Preview 4 Released - Shiju Varghese's Blog. Retrieved from http://weblogs.asp.net/shijuvarghese/archive/2008/07/16/asp-net-mvc-preview-4-released.aspx 页面存档备份,存于
  10. ASP.NET MVC CodePlex Preview 5 Release Notes. Retrieved from http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=aspnet&ReleaseId=16775 页面存档备份,存于.
  11. http://go.microsoft.com/fwlink/?LinkID=129910&clcid=0x409%5B%5D
  12. http://go.microsoft.com/fwlink/?LinkID=141184&clcid=0x409
  13. http://go.microsoft.com/fwlink/?LinkId=144443%5B%5D
  14. http://go.microsoft.com/fwlink/?LinkId=144444%5B%5D
  15. http://go.microsoft.com/fwlink/?LinkID=154409%5B%5D
  16. . [2009-11-18]. (原始内容存档于2009-11-21).
  17. . [2010-04-02]. (原始内容存档于2010-04-01).
  18. . [2010-11-24]. (原始内容存档于2010-11-22).
  19. . [2010-11-25]. (原始内容存档于2012-07-09).
  20. . [2011-01-19]. (原始内容存档于2011-01-19).
  21. . [2012-06-21]. (原始内容存档于2012-05-29).
  22. . [2012-06-21]. (原始内容存档于2012-06-21).
  23. . [2012-06-21]. (原始内容存档于2012-06-19).
  24. . [2014-02-05]. (原始内容存档于2014-02-22).
  25. . [2014-02-05]. (原始内容存档于2014-02-22).
  26. . [2016-02-16]. (原始内容存档于2016-02-23).
  27. . Microsoft. 12 February 2018 [14 March 2018]. (原始内容存档于2019-01-23).
  28. . Microsoft. 2 May 2018 [4 May 2018]. (原始内容存档于2019-01-17).
  29. . [2009-08-31]. (原始内容存档于2012-03-26).
  30. . [2010-11-08]. (原始内容存档于2010-11-10).

外部网站

View engines

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.