理解模型,檢視和控制器(C#)

Web開發者發表於2012-03-05

  這篇文章向你提供ASP.NET MVC 模型,檢視和控制的高度概覽。換句話說,解釋一下ASP.NET MVC中的 ‘M’, ‘V’, 和 ‘C’。

  看完這篇文章以後,你應該就能理解ASP.NET MVC的不同部分是如何共同工作的。而且你也應該能夠理解ASP.NET MVC程式的架構與ASP.NET Web窗體程式或ASP程式有如何的不同。

 示例 ASP.NET MVC 應用程式

  用以建立ASP.NET MVC Web程式的預設的 Visual Studio 模板包括一個極其簡單的示例程式,可以用來理解ASP.NET MVC Web程式的不同部分。我們在這個教程裡就利用這個簡單程式吧。

  執行Visual Studio 2008, 選擇“檔案”,“新建”(見圖1),用MVC模板建立ASP.NET MVC程式。在“新建專案”對話方塊中,在“專案型別(P)”(Visual Basic 或者C#)中選擇你喜歡的程式語言,並在“模板”下選擇 ASP.NET MVC Web Application 。點選“確定”按鈕。

 
圖1 新建專案對話方塊

  建立完新的 ASP.NET MVC 程式後, 出現Create Unit Test Project 對話方塊(見圖2). 這個對話方塊會在解決方案中為你建立一個單獨的用來測試你的ASP.NET MVC程式的專案。選擇選項 No, do not create a unit test project 並單擊 OK 按鈕。

 
圖2 建立單元測試對話方塊

  ASP.NET MVC 程式建立完成。你會在解決方案資源管理器視窗中看到幾個資料夾和檔案。特別是你會看到三個分別名為Models,Views和Controllers的資料夾。顧名思義,這三個資料夾包含了實現模型,檢視和控制器的檔案。

  如果你展開Controllers資料夾,你會看到一個名為AccountController.cs和一個名為HomeControllers.cs的檔案。展開Views資料夾,會看到三個分別名為Account,Home和Shared的子資料夾。展開Home資料夾,會看到兩個分別名為About.aspx和Index.aspx的檔案(見圖3)。這些檔案組成了包括預設ASP.NET MVC模板的示例程式。

 
圖3 解決方案資源管理器視窗

  選擇“除錯”,“啟動除錯”執行示例程式。或者按F5鍵也可以。

  第一次執行 ASP.NET 程式時,會出現圖4所示的對話方塊,建議你啟動除錯。 點選“確定”按鈕程式就會執行起來了。

 
圖4 除錯未啟動對話方塊

  執行ASP.NET MVC 程式時, Visual Studio 會在瀏覽器執行你的程式。示例程式包括2個頁面:Index頁和About頁。程式首次啟動時,出現Index頁(見圖5)。你可以點選程式右上方的選單連結導航到About頁。


圖5 Index 頁

  注意瀏覽器位址列的URL,當點選About選單連結時,位址列中的URL變為 /Home/About。

  關閉瀏覽器視窗回到 Visual Studio,你找不到路徑Home/About的檔案。這個檔案不存在,這怎麼可能呢?

 一個URL不等於一個頁

  生成傳統的ASP.NEW Web窗體程式或ASP程式時,一個URL對應一個網頁。如果向伺服器一個名為 SomePage.aspx的頁面發起請求 ,那麼磁碟裡最好存在這麼一個名為SomePage.aspx的頁面。如果 SomePage.aspx 檔案不存在,將會得到一個醜陋的 404 – Page Not Found 錯誤。

  相反,生成 ASP.NET MVC 程式時,在你輸入瀏覽器地址的URL和你要在程式裡找的檔案之間並沒有對應關係。在

  ASP.NET MVC 程式中, 一個URL並不對應磁碟上的頁而是對應一個控制器action。

  在傳統 ASP.NET 或者 ASP 程式中, 瀏覽器請求被對映到頁面。相反,在 ASP.NET MVC 程式中, 瀏覽器請求被對映到控制器action。 ASP.NET Web 窗體程式以內容為中心。 相反,ASP.NET MVC 程式以程式邏輯為中心。

 理解ASP.NET Routing

  瀏覽器請求通過一個名為 ASP.NET Routing 的ASP.NET 框架特性來獲得控制器action的對映。 ASP.NET Routing 被 ASP.NET MVC 框架用來對傳入控制器action的請求進行路由。

  ASP.NET Routing 用一個路由表來處理傳入的請求。當web程式第一次執行時這個路由表就會被建立。 它是在 Global.asax 檔案中被建立的。預設的 MVC Global.asax 檔案如程式碼1所示。

 程式碼1 – Global.asax

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MvcApplication1
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );
        }

        protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
        }
    }
}

  ASP.NET 程式首次啟動時, Application_Start() 方法會被呼叫。 在程式碼 1中, 此方法呼叫 RegisterRoutes() 方法建立預設路由表。

  預設路由表只包括一個路由。這個預設的路由將傳入的請求分為三段(一個URL段就是兩個斜槓間的任何東西)。第一段對映到控制器名,第二段對映到action名,最後一段對映到一個傳到action的名為Id的引數。

  例如,考慮以下URL:

  /Product/Details/3

  這個 URL 被解析為類似這樣的3個引數:

  Controller = Product

  Action = Details

  Id = 3

  Global.asax 檔案中定義的預設路由包括所有三個引數的預設值。預設的控制器是 Home, 預設的 Action 是 Index, 預設的 Id 是空字串。心裡想著這些預設值,思考一下下面的URL是怎麼解析的:

  /Employee

  這個 URL 被解析成類似這樣的三個引數:

  Controller = Employee

  Action = Index

  Id =

  最後,如果你不輸入任何URL(例如,http://localhost)就開啟 ASP.NET MVC 程式的話URL就像這樣解析:

  Controller = Home

  Action = Index

  Id =

  這個請求就被路由到HomeController類的 Index() action 中。

 理解控制器

  控制器負責控制使用者與MVC程式互動的方式。控制器包括了ASP.NET MVC程式的流控制邏輯。控制器決定當使用者傳送一個瀏覽器請求時返回什麼響應。控制器就是一個類(例如,一個Visual Basic或者C#類)。樣例 ASP.NET MVC 程式包括一個位於Controllers資料夾中名為 HomeController.cs 的控制器。 HomeController.cs 檔案內容轉載在程式碼 2中。

 程式碼 2 – HomeController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

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

  注意 HomeController 有兩個方法,名為Index() 和About().。這兩個方法對應由控制器暴露的兩個action。 URL /Home/Index 呼叫 HomeController.Index() 方法而URL/ Home/ About 呼叫 HomeController.About() 方法。

  控制器中的任何公共方法都被暴露為控制器action。對此你要特別小心。這意味著人們只要通過訪問網際網路,在瀏覽器中輸入正確的URL,就可以呼叫控制器中的任何公共方法。

 理解檢視

  由HomeController暴露的 Index() 和About() 這兩個action都返回一個檢視。檢視包括HTML標記和傳送到瀏覽器的內容。在ASP.NET MVC程式中檢視等同於一個頁面。你必須在正確的地方建立檢視。HomeController.Index() action 返回一個位於以下路徑的檢視:

  /Views/Home/Index.aspx

  HomeController.About() action 返回一個位於以下路徑的檢視:

  /Views/Home/About.aspx

  通常,如果你想為控制器action返回檢視,那麼你需要在Views資料夾下建立一個與控制器同名的子資料夾。在此子資料夾內,你得建立一個與控制器action同名的 .aspx 檔案。

  程式碼3 中的檔案包含 About.aspx 檢視。

  程式碼3 – About.aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="aboutContent" ContentPlaceHolderID="MainContent" runat="server">
    <h2>About</h2>
    <p>
        Put content here.
    </p>
</asp:Content>

  如果你忽略程式碼3的第一行,檢視的其餘部分包含了標準的HTML。你可以輸入任何你想要的HTML來修改檢視的內容。

  檢視和ASP或ASP.NET Web窗體中的頁面很相似。檢視可以包含HTML內容和指令碼。你可以用你喜歡的程式語言寫指令碼(例如,C#或Visual Basic .NET)。使用指令碼來顯示動態內容,例如資料庫資料。

 理解模型

  我們已經討論了控制器和檢視。最後一個話題就是模型了。什麼是MVC模型?

  MVC 模型包含程式中的所有邏輯,而這些邏輯並不包含在檢視或控制器中。模型應該包含所有程式業務邏輯,驗證邏輯和資料庫訪問邏輯。例如,如果你用 Microsoft Entity Framework 來訪問資料庫,那麼你要在Models資料夾中建立 Entity Framework 類 ( .edmx 檔案) 。

  檢視應該僅僅包含生成使用者介面的邏輯。控制器應該僅僅包含返回正確檢視的最小邏輯或者將使用者重定向到其他action(流控制)。其它的任何事情都應該包含在模型中。

  通常,你應該為“胖”模型和“瘦”控制器而努力。控制器方法應該只包含幾行程式碼。如果控制器action變得太“胖”的話,那麼就應該考慮將邏輯挪出到Models資料夾中的一個新類中。

 總結

  這篇教程提供給你ASP.NET MVC Web程式不同部分的高度概覽。你學到了 ASP.NET Routing 如何將傳入的瀏覽器請求對映到特定的控制器action。你學到了控制器如何編配,檢視如何返回到瀏覽器。最後,你學到了模型如何包含程式業務,驗證和資料庫訪問邏輯。

相關文章