[ASP.NET][MVC] ASP.NET MVC (1) : 如何學 ASP.NET MVC ?

ASP.NET MVC 最近似乎慢慢的有變紅的趨勢,也開始有不少人在詢問如何學習 ASP.NET MVC,之前我也寫過一篇簡單的介紹文,說 ASP.NET MVC 比較適合寫過 ASP, JSP, PHP 等的開發人員,因為它的處理方式和傳統的 ASP.NET Web Form 截然不同,首先就是 MVC 的概念,因為這會涉及資料在 MVC Framework 內的流動方式,另外一個就是習慣導向的設計,微軟認為習慣導向可以加快開發人員的開發速度,所以在一個 ASP.NET MVC 專案的配置,和平常寫 ASP.NET Web Form 有一定的差異。

ASP.NET MVC 最近似乎慢慢的有變紅的趨勢,也開始有不少人在詢問如何學習 ASP.NET MVC,之前我也寫過一篇簡單的介紹文,說 ASP.NET MVC 比較適合寫過 ASP, JSP, PHP 等的開發人員,因為它的處理方式和傳統的 ASP.NET Web Form 截然不同,首先就是 MVC 的概念,因為這會涉及資料在 MVC Framework 內的流動方式,另外一個就是習慣導向的設計,微軟認為習慣導向可以加快開發人員的開發速度,所以在一個 ASP.NET MVC 專案的配置,和平常寫 ASP.NET Web Form 有一定的差異。

所以,我把 ASP.NET MVC 應用程式的過程,繪製成一張簡單的流程圖,裡面包含了在 ASP.NET MVC 中會用到的技術。

image

首先,用戶端使用 URL 向 MVC 應用程式提交要求,URL 的格式通常是 {root}/{controller_name}/{action_name}/{parameters},所以 MVC 應用程式的 URL 看起來都會像 http://www.mymvcapp.com/Home/Index 或是 http://www.mymvcapp.com/Product/Details/1028 這樣,一來可以簡化 URL,二來可以直接明確對應 Controller 和 Action 以及必要的參數,這些資料會由 ASP.NET Routing 來做指令繞送,不過事實上 ASP.NET Routing 是一個 HTTP Module,它會攔下所有的 URL Request,並將它交給 UrlRoutingHandler 處理,而 UrlRoutingHandler 會將註冊在路由表中的路徑對應與要處理的 HTTP Handler 取出,將控制權直接交給該 HTTP Handler,而路由表必須在應用程式生成時就登錄,所以在 Global.asax 會放這樣的程式:

protected void Application_Start(object sender, EventArgs e)
{
    RegisterRoutes();
}

private static void RegisterRoutes()
{
    RouteTable.Routes.Add(
        "Recipe",
        new Route("recipe/{name}", 
                  new RecipeRouteHandler(
                      "~/WebForms/RecipeDisplay.aspx")));
}

 

在 .NET Framework 4.0 時,ASP.NET Routing 可支援到 Web Form,所以 Web Form 可利用它享有 URL Rewriting 的能力,而 ASP.NET MVC 更是在一開始就支援,而 MVC 的接受端是 MvcRouteHandler,它會再把控制權交給 MvcHandler,這也是它真正處理 MVC 動作流的部份,在它的 ProcessRequest() 中,就是 Controller 的生成與執行。

protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
    this.AddVersionHeader(httpContext);
    string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
    IControllerFactory controllerFactory = this.ControllerBuilder.GetControllerFactory();
    IController controller = controllerFactory.CreateController(
           this.RequestContext, requiredString);
    if (controller == null)
    {
        throw new InvalidOperationException(
              string.Format(CultureInfo.CurrentUICulture, 
              MvcResources.ControllerBuilder_FactoryReturnedNull,
              new object[] { controllerFactory.GetType(), requiredString }));
    }
    try
    {
        controller.Execute(this.RequestContext);
    }
    finally
    {
        controllerFactory.ReleaseController(controller);
    }
}

Controller 生成後,會由 Controller.Execute() 執行動作,也就是 Action 所指定的部份,由 ControllerActionInvoker 來執行,它會處理參數的對應,ActionFilter的設定檢查等,而這時被呼叫的 Action 要決定資料的來源 (Model),以及要回傳的 ActionResult,例如:

namespace MvcApplication1.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewData["Title"] = "Home Page";
            ViewData["Message"] = "Welcome to ASP.NET MVC!";

            return View();
        }

        public ActionResult About()
        {
            ViewData["Title"] = "About Page";

            return View();
        }
    }
}

 

Index() 決定了回傳的是基本的 View (即 ViewActionResult 物件),表示會去找 Views\Home 資料夾下的 Index.aspx,由它來決定回傳的內容是什麼,同例的 About() 也是一樣的作法,但找的是 Views\Home 資料夾下的 About.aspx。

而 Action 完成動作後,ControllerActionInvoker 會呼叫 CreateActionResult() 來進行後續動作,這時控制權就會落在 View 上,而為了有最大的彈性,View 看起來就會像 ASP 時代一樣:

 

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Product Index</title>
</head>
<body>
    <div>
    
    <%= Html.Encode(ViewData["message"]) %>
    
    </div>
</body>
</html>

 

而在 ASP.NET MVC 3 時,微軟更引進了 Razor Engine,讓編寫 View 程式的工作,更像是在寫一般程式,而且 Razor 在混搭 HTML 指令的能力比原本的 View Engine 要強大許多。

@model dynamic
           
@{
    ViewBag.Title = "IndexNotStonglyTyped";
}

<h2>Index Not Stongly Typed</h2>

<p>
 <ul>
@foreach (var blog in Model) {
   <li>
    <a href="@blog.URL">@blog.Name</a>
   </li>   
}
 </ul>
</p>

 

之所以要講這麼多,就是要讓想學 ASP.NET MVC 的人知道這個技術會涵蓋到的地方,以及在動作流中哪些東西是必要的,像 ASP.NET Routing 是一定要做的,沒有它的話,MVC 會無法知道要對應哪個 Controller以及要執行哪個 Action,而 Controller, View 和 Model 都要依習慣導向的設計規則,View 的部份則是要熟悉 Razor 語法或傳統的 View Engine 語法等。

而寫過 ASP.NET Web Form 的開發人員如要學習 MVC,則必須要先習慣沒有 Event Model 的 ASP.NET Programming,建議是先寫過幾個不用 ASP.NET Control 的 Web 應用程式後,再來接觸 MVC 會比較輕鬆且也能較快入門。

PS: 以上部份程式是來自 System.Web.Mvc.dll 中的原始碼,由於微軟已開放 System.Web.Mvc.dll 的程式碼,所以引用過來沒有問題。

Reference:

國外來源:

http://www.asp.net
http://www.asp.net/mvc
http://weblogs.asp.net/scottgu/archive/tags/MVC/
http://www.asp.net/mvc/tutorials

國內也有許多寫 ASP.NET MVC 高手的文章,例如:

http://demo.tc/List/Coding/MVC
http://www.dotblogs.com.tw/alonstar/category/3677.aspx
http://charlesbc.blogspot.com/search/label/Asp.Net%20MVC
http://blog.kkbruce.net/search/label/MVC
http://www.dotblogs.com.tw/wadehuang36/Default.aspx