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、PHP、JSP、Perl 這些 Web 開發工具的開發人員來說，相對的不容易入門。ASP.NET MVC 的第一個版本於 2009 年 3 月 17 日釋出 RTM 版本，最新的 ASP.NET MVC 5.2 則是於 2014 年 12 月 24 日正式發行。

微軟於 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 方法來執行工作。

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 等介面的物件。

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

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 物件以 IView 與 IViewDataContainer 等介面為主，並且以 ASP.NET 的各式前端介面為主要輸出工具，基於 MVC 的 View 彈性化設計考量，以往在 ASP.NET Web Form 的程式碼與 HTML 分離模式將不再存在，而是將程式碼與 HTML 混合的方式設計，讓開發人員可以更精確的對 View 進行控制，而目前 ASP.NET MVC 支援的 View 有下列幾種：

.aspx 網頁，由 ViewPage 來支援。
.ascx 使用者控制項，由 ViewUserControl 來支援。
.master 主版頁面，由 ViewMasterPage 來支援。

每個 View 物件都會內含一個泛型的引數，用來裝載要呈現的資料 (即 Model)，然後使用類似下面的方式來呈現資料：

My MVC Application

技術

在 ASP.NET MVC 架構中，除了 Controller、Model 與 View 三個主要部份以外，還包含了許多技術以讓這三層得以整合並互動運作。

2.1 Controller

Controller 在 ASP.NET MVC 應用程式中是負責中控的角色，也是來自使用者端 HTTP 要求的處理核心，因此有許多處理與轉向 HTTP 要求的輔助技術在 Controller 層次都會使用到。

2.1.1 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

2.1.2 動作與方法直接整合

ASP.NET MVC 利用了中介資料的技術，直接將方法對應到指定的 HTTP 動詞 (GET/POST/PUT/DELETE/HEAD 等)，MvcHandler 會判斷要求的類別，並將它交給 URL 中指定的方法來處理。目前 MVC Framework 可用下列的方式指定（均包含在 HttpVerbs 列舉型別中）：

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

2.1.3 將資料模型與展示層直接包裝

ViewPage、ViewMasterPage、ViewUserControl 等展示物件都支援泛型物件，可以直接裝載 Model 資料傳遞至前端輸出，可簡化處理 Model 與 View 之間整合的動作，只要一個引數就可以將資料傳給 View：

public ActionResult GetList

{return View (BlogDataModel);

}

Function GetList As ActionResult

Return View (BlogDataModel)

End Function

2.2 Model

在 ASP.NET MVC 中，Model 相對不設限，可以使用內建的資料結構以及自訂的資料類別，也可以是一個商業物件，因此 Model 的彈性相當大，除了前述的資料結構外，微軟新發展的一些資料存取方式也可以應用在 Model 中，像是 ADO.NET Entity Framework 與 LINQ 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 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;}

}

}

}

2.3 View

由於 View 是直接呈現給使用者，因此與使用者互動的部份都要由此層處理，包含資料的輸出以及以使用者端操作為主的回應（例如指令碼）等。

2.3.1 HTML 工具類別

HTML 工具類別在 View 中是很重要的輸出工具，它內建了輔助產生 HTML 標籤的工具方法，多數的 HTML 語法都可以利用它來產生，包含像連結 、表單 以及表單控制項等等。HTML 工具是以 HtmlHelper 類別為核心，並配合 System.Web.Mvc.Html 名稱空間的方法，以延伸方法 (Extension Method) 的方式，讓產生 HTML 的程式就有如呼叫方法般簡單：

Index

Id

Name

2.3.2 資料驗證

View 的 HTML 工具可以配合 Model 處理資料驗證的結果，在 ASP.NET 中常用的 ValidationSummary 在這裡也支援，而且 MVC 的架構讓驗證資訊的輸出也更加彈性：

Create

Fields

Name:

Required

Age:

Required

Street:

City:

State:

Zipcode:

Phone:

Required

Email:

Required

2.3.3 不同型別的輸出

每一個 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 等官方網站都採用它來開發。另外，stackoverflow.com 以及 codeplex.com 這兩個網站也是採用 ASP.NET MVC Framework。

版本歷程

授權

ASP.NET MVC Framework 雖然是 ASP.NET 的一部份，不過它的原始碼是透過 Microsoft Public License (MS-PL) 的授權模式公開，因此在 MS-PL 授權的範圍內，任何人是可以去檢視與修改它的原始碼的。

ASP.NET MVC Razor Engine

微軟在 2010 年 7 月 2 日由 Scott Guthrie 發表新的 MVC 繪製引擎 (Render Engine)：Razor Engine，它已內建於 ASP.NET MVC 3.0 中發布，它具有下列功能：

更輕量化且直覺的語法，減少在 View 中輸出資料時使用的語法，讓 View 的指令更加簡潔，例如使用 "@" + 變數名稱 的方式，就可以輸出程式中的變數，不必再用 來設定。如果程式有多行，可以使用 @{ } 的方式來設定。
容易學習。
可相容於現在的程式語言 (ex: C#)。
透過 Visual Studio，可享有 Intellisense 能力。
可混用 HTML 與程式語言指令。
可用各種不同的文字編輯器編輯。
具有單元測試的能力。