本文章是由機器翻譯。

table.one { table-layout:fixed;width: 600px; font-size: 14px; color: #333; margin-bottom: 5px; } table.two { table-layout:fixed;width: 600px; border-top: 3px; border-top-color: #0569b5; border-top-style:solid; margin-bottom: 10px; } .tdwidth{ width:400px; } .tdwidth1{ width: 220px; } .SidebarInsights { border: 2px solid #008080; padding: 10px 20px 20px 20px; background-color: #e1e8f5; margin: 10px 0px 10px 0px; font-family: Verdana, Arial; font-size: 12px; padding-bottom: 7px; line-height: 16px; color: #333333; }

ASP.NET 有絕招

[生命和的 ASP.NET MVC 控制站的時間

Scott Allen

可從 MSDN 程式庫 的程式碼下載
瀏覽線上的程式碼

本文根據 ASP.NET MVC 架構鮮版。詳細資料如有變更。

內容

Factory 會造成所有的路由
Factory 的擴充性
執行是 Just 開頭
選取的屬性 (Attribute)
篩選屬性 (Attribute)
自訂動作的篩選器
取得結果
在動作是透過

控制站都是在 lynchpins 模型檢視控制器 (MVC) 設計模式。它們是在前一行先接收用戶端的要求] 和 [到應用程式的網域邏輯和資料所在的模型的指示,然後轉譯要求。控制站負責也選取檢視的使用者顯示資訊。

這的篇文章,我們將可以仔細分析 ASP.NET MVC 架構並可查看控制站的運作方式。我會說明在 Framework 與您的控制站的互動方式和如何您可能會影響這些互動。我將探討控制站的工廠、 控制器的動作及動作的篩選器動作以及結果。

我將會相當深入挖掘中,因此如果您正在尋找一般的 ASP.NET MVC 架構,簡介請參閱 Chris Tavares 的文件 」建置 Web 應用程式,而 Web Form."

Factory 會造成所有的路由

很難談不談論的路由的控制器的存留。路由表在 ASP.NET 應用程式中的會包含 ASP.NET 從傳入 URL 中擷取資訊,並將直接要求適當的軟體元件的路由模組所需的資訊。在 1 月的專欄,我探討使用 ASP.NET 路由模組,與 Web 表單 (「以 ASP.NET Web Form 路由".) 該的資料行中的請我建立我自己的路由處理常式,以執行 Web Form,但 ASP.NET MVC 架構提供路由處理常式,最後將會直接其中我們控制站的要求]。

處理要求這個 MVC 路由的處理常式,您要在應用程式啟動時,設定路由表。MVC 專案範本所提供,預設路由的設定存在於 Global.asax 檔案中,及 [圖 1 ] 所示。

[圖 1: 預設路由組態

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",                                             
        "{controller}/{action}/{id}",                          
        new { controller = "Home", action = "Index", id = "" } 
    );            

}

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

其中一個路由的組態項目, [圖 1 ] 中會是名為的 URL] 範本的預設路由 」 {控制站} / 動作} / {識別碼} 」。 這個 URL 的範本會是路由引擎將用來第一個,請參閱如果這個路由符合的項目的傳入的 URL 模式。 URL,將會符合這類路由是 http://localhost/home/Index/。 當路由引擎會找到相符項目時, 它會再次使用 URL 範本模式提起從傳入的 URL 參數。 在這個範例中,字串 「 首頁 」 會變成控制器參數,因為它是在 {控制站} 的位置中,而且字串 「 索引成為 Action 參數。

匿名型別的物件建構為 MapRoute 將第三個參數會表示路由引擎在 URL 中找不到指定的參數,如果使用預設值。 在 http://localhost/home/Index/ 的情況下路由引擎不尋找在的 URL 」 識別碼資訊,但是它仍會傳遞以及預設值為空字串的識別碼參數]。 路由引擎會透過一個 RouteData 物件,將所有這些參數傳遞至路由的處理常式。

請注意路由引擎會知道任何有關 ASP.NET MVC 重要的。 引擎的唯一工作是分析 URL,並傳遞至資料的路由傳送處理常式的控制項。 MapRoute 方法內之 [圖 1 RegisterRoutes 方法叫用的會是延伸方法,由 MVC) 架構提供。 註冊 MapRoute 每個路由設定為使用 MvcRouteHandler 物件 — 這是 MVC Framework 所提供的路由傳送處理常式。 如您所見 1 月資料行中,它是要尋找要求的 HTTP 處理常式的路由傳送處理常式的工作 — 也就是實作 IHttpHandler 介面的物件。 MVC 應用程式,請這個物件將會型別 MvcHandler 的物件,而且在 MvcHandler 是其中處理成為有趣]。

[圖 2 ] 顯示一般 MVC 要求的處理流程。 控制項會到達,MvcHandler,the MvcHandler 時能夠從稍早在處理路由模組所產生,RouteData 中抽選控制器參數。 處理常式最後會將這個控制器] 參數,是字串值,傳送到控制器 Factory 中。 它是再建構,並傳回控制器 Factory 的責任。 MVC 應用程式中的所有控制站,實作 IController 介面。

fig02.gif

[圖 2] 的一般 MVC 要求的控制流程

.MVC Framework 會提供一個預設控制器 Factory (適當命名為 DefaultControllerFactory),將會尋找所有類型的實作 IController,並將其名稱結束控制站的 appdomain 中所有組件中都搜尋。 因此,如果您知道要尋找 「 首頁 」 的控制器工廠,Factory 可以傳回 HomeController 無論命名空間或它存在於的組件的類別的新執行個體化的執行個體,只要它實作 IController。 這個問題屬於 MVC 的 「 使用慣例,透過組態 」 樣式。 沒有更 Factory 的故事,但是讓我們先完成 MvcHandler 處理。

一旦在 MvcHandler 的 IController 參考從工廠,它叫用控制器和等候工作的魔法,控制站上執行。 當執行為完整,[MvcHandler 會檢查如果控制器實作的 IDisposable 介面的而且如果時,叫會用 Dispose 來清除 Unmanaged 資源控制站上。

Factory 的擴充性

控制器 Factory 會是一個金鑰的擴充性點,MVC ASP.NET Framework 中。 雖然 Framework 所提供的預設 Factory 可以在您的解決方案中找到任何地方的 HomeController,它只能具現化,HomeController 如果您提供無參數的建構函式。 這項限制會是小組遵循相依性的反向原則,並插入透過其建構函式的控制站的相依性的問題。 例如,考慮 EmployeeController (所示 [圖 3 提供) 需要有人將一個的記錄元件傳遞至其唯一的建構函式。

[圖 3 EmployeeController

public class EmployeeController : IController
{
    public EmployeeController(ILogger logger)
    {
        _logger = logger;
    }

    public void Execute(RequestContext requestContext)
    {
        // ...
    }

    ILogger _logger;
}

幸運的是,您可以建立自訂的 Factory。 實作 IControllerFactory 介面的任何類別都是一個的候選,而且您僅需要實作 CreateController 和 ReleaseController 方法。 不過,反向的控制項的容器,例如 StructureMap、 Unity、 Ninject 及城堡專案的 Windsor 隨時可,並會在這個案例中為完整適合。 事實上, CodePlex 上的 MVC contrib 專案 包含 IControllerFactory 上面所列之容器的所有的實作。

如果要做為您的控制項容器的反向的 StructureMap 您可以參考 StructureMap 和 MvcContrib.StructureMap) 組件,然後撰寫程式碼,如 [圖 4 ] 所示。 此清單中的 InitializeContainer 方法先告訴 StructureMap 的 ILogger 必要時,請使用 SqlServerLogger 型別。 程式碼,然後設定控制器 Factory,整個應用程式使用的目前的 ControllerBuilder SetControllerFactory 方法。 過程要求在 MvcHandler 會要求這個相同的 ControllerBuilder 目前設定的 Factory,並使用 StructureMapControllerFactory,以取代預設 Framework Factory。

[圖 4 初始化容器

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

private void InitializeContainer()
{
    StructureMapConfiguration
        .ForRequestedType<ILogger>()
        .TheDefaultIsConcreteType<SqlServerLogger>();

    ControllerBuilder.Current.SetControllerFactory(
        new StructureMapControllerFactory());
}

從 MVC contrib 專案在 StructureMapControllerFactory 不會繼承 MVC 架構的預設控制器 Factory,並仍使用我稍早描述尋找控制器型別具現化時,慣例。不過,Factory 會用來 StructureMap 具現化的控制站並 StructureMap 會知道如何使用參數型建構函式。[圖 4 ] 所示的組態是一切處理 http://localhost/Employee/ 的要求。StructureMap 會產生 [圖 3 在 EmployeeController,藉由傳入 SqlServerLogger 參考。

fig05.gif

[圖 5 類別階層架構

執行是 Just 開頭

稍早我所述,MvcHandler 叫用控制站的 Execute 方法,等候,然後清除。這是因為在 MvcHandler 只知道透過 IController 介面的控制站。如果要撰寫您的應用程式在這個層級則您無法直接衍生所有從 IController 介面的控制站,並提供在 Execute 方法實作。不過,ASP.NET MVC 架構所提供的更豐富的執行模型,控制站,透過的 [圖 5 ] 所示的類別階層架構。

預設的情況下,您將加入至 ASP.NET MVC 專案的控制站會衍生自 System.Web.mvc.controller 類別。加入新的控制站是在 [方案總管中的的 [控制器] 資料夾上按一下滑鼠右鍵,並選取 [新增] 其中一個方法 | 控制站可讓您在 [圖 6 顯示對話方塊。請記住的控制器 Factory,找到您的控制站名稱之後必須搭配控制器。

控制站的基底類別,引入了動作的概念。動作會是控制站上做為 MVC 應用程式中最後的要求目的地的方法。稍早,我指出 ASP.NET 的路由模組將會移除 「 首頁 」 為控制器參數,從 URL 的 http://localhost/home/Index/ 出。這是足夠的資訊,適當的控制器來路由傳送要求。路由的模組,也會挑選出 「 索引 」 為動作參數。當 [MvcHandler 會告訴 HomeController,執行時,是由基底的控制器) 類別,檢查此動作的參數,和在叫用適當的控制器的方法內撰寫邏輯。大部分的這個動作的路由邏輯,位於公用 ControllerActionInvoker 類別內。

fig06.gif

[圖 6 加入控制器

[圖 7 ] 是由 ASP.NET MVC 專案範本,HomeController。這些公用執行個體方法,索引,並在代表用戶端要求的家庭 / 索引時,Framework 會叫用的動作,關於,/ 和首頁 / 關於 /,分別。任何公用執行個體方法可以作為一個控制器的動作,只要在 Framework 可以判斷特定的動作是正確叫用 (Invoke) 動作 (也就是說小心方法多載)。其他規則在播放時,有.Framework 正在搜尋要叫用 (Invoke) 的動作。您可以影響架構的所選擇的動作,建立其他規則動作選取,並管理您的動作使用屬性 (Attribute) 的行為。

[圖 7 HomeController

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

        return View();
    }

    public ActionResult About()
    {
        return View();
    }
}

選取的屬性 (Attribute)

您可以裝飾提供 Framework 其他資訊,它會選取要叫用 (Invoke) 的動作時要考慮的選取器屬性在控制器動作。 例如,至控制器的方法中加入 [NonAction] 屬性將會導致方法從可用的動作清單中排除。 您也可以在特定的動作名稱提供方法。 預設狀況下,方法的名稱也是動作名稱,但如果您將 [ActionName("Help")] 在您 HomeController 相關方法,則 about 」 不再為控制器正確的動作。 而,有關方法的動作名稱會是 [說明],而且,Framework 會叫用,有關方法的要求,例如 / 首頁 / 說明 /。

其中的特別重要的選取器屬性是在 AcceptVerbs 屬性。 這個屬性只允許將 Framework 動詞命令在屬性中列出的其中一個符合目前 HTTP 要求的動詞命令時,請選取的動作。 例如,裝飾為方法 with[AcceptVerbs(HttpVerbs.post)] 表示的方法可以叫只用做為 HTTP POST 作業的動作。 很重要以選取您的控制器動作,適當的動詞命令特別是如果動作會修改在伺服器上的狀態。 可能進一步,請參魷 \ cs6 \ f1 \ cf6 \ lang1024 Stephen Walther ASP.NET MVC 提示 #46 .

篩選屬性 (Attribute)

動作的篩選器將是屬性的您,另一個的型別,您可以將執行的動作。 動作的篩選器您可以加入快取、 驗證和錯誤處理行為,您使用宣告式程式設計模型的動作。 篩選器屬性的範例都是在 [圖 7 ] 中的 [HomeController HandleError] 屬性。 您可以將這個屬性 (Attribute) 套用至個別的動作,或將屬性加入要套用 [行為] 的控制器的所有動作至 Controller 類別至。

當一個 HandleError 屬性出現在 [動作] 上,而且動作會擲回例外狀況時 MVC 架構會尋找具有 「 錯誤 」 的名稱在檢視-控制器的檢視資料夾,中的第一個,然後也在共用的檢視資料夾中。 [錯誤] 檢視可讓您顯示易懂的錯誤網頁給使用者。 您也可以將例外狀況對應到特定的檢視,使用更明確的 HandleError 屬性。 例如,[HandleError(ExceptionType=typeof(SqlException),檢視 ="DatabaseError)] 會對應至名為 DatabaseError 」 檢視的未處理的 SqlException。 動作的篩選器 MVC Framework 所提供的其餘部分是由 [圖 8所述。

[圖 8 個動作的篩選器
名稱 描述
OutputCacheAttribute 類似於在 ASP.NET Web Form 中 OutputCache 指示詞。 OutputCache 屬性 (Attribute) 允許快取控制站的輸出.MVC Framework。
ValidateInputAttribute 類似於 Web Form 中 ValidateRequest 屬性。 預設的情況下,MVC) 架構會檢查傳入的 HTTP 要求的 HTML 或其他危險的輸入。 如果偵測到,將會引發例外狀況。 您可以使用這個屬性,停用要求驗證。
AuthorizeAttribute authorize 屬性可讓您將控制器的動作上的宣告式的授權檢查。 屬性可以限制特定角色的使用者的動作。 當您建立只可供系統管理員的角色中的使用者的動作時,您可以使用這個屬性。
ValidateAntiForgeryTokenAttribute 這個屬性可以是其中一個解決方案,協助防止跨站台的一半要求 forgeries (CSRF)。 它可讓驗證的使用者特定語彙基元的 HTTP POST,Framework。 如需有關 CSRFs 的詳細資訊,請參閱 < 防止跨站台要求偽造 (CSFR) 使用 ASP.NET MVC AntiForgeryToken() Helper ."

自訂動作的篩選器

您可以建立您自己動作篩選器括住的動作,使用自訂邏輯。 [圖 9 ] 中的程式碼都是簡單的記錄動作篩選器,可以寫入輸出視窗的 Visual Studio 在偵錯期間代碼。 我們也可以套用這個屬性的個別的動作,或我們可以將這個屬性 (Attribute) 放在控制器類別在控制器上的所有動作的記錄]。

[圖 9 A 記錄動作的篩選器

public class LogAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Log("Action Executing", filterContext.RouteData);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        Log("Action Executed", filterContext.RouteData);
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        Log("Result Executing", filterContext.RouteData);
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        Log("Result Executed", filterContext.RouteData);            
    }

    void Log(string stageName, RouteData routeData)
    {
        Debug.WriteLine(
            String.Format("{0}::{1} - {2}", 
                routeData.Values["controller"],
                routeData.Values["action"],
                stageName));
    }        
}

您可以看到有四個基底 ActionFilter 類別所提供的虛擬方法。您可以覆寫一或多個不只是建置前和後續處理的控制器動作,但也套用這些方法,並在後續處理控制器動作的結果。之前的動作執行、 OnActionExecuting 方法會引發,並動作完成時,OnActionExecuted 方法將引發 (及即使動作,擲回未處理例外狀況,會引發)。同樣地,結果執行和 OnResultExecuted 方法會引發之後之前,會引發 OnResultExecuting 方法。

內容參數傳遞至動作的篩選器方法可讓您檢查 HTTP 要求、 HTTP 內容、 在路由傳送的資料和更多。擲回的例外狀況,從其中一個這些方法將會中止要求處理流程。例外狀況是一個很有用的工具,如果您正在撰寫的 ActionFilter 檢查先決條件,在環境中。

取得結果

MVC 控制器動作的成功執行會產生衍生自 ActionResult 的物件。呈現檢視,並將重新導向至新的 URL 的瀏覽器是 [兩個的您可能想要從您的控制器結果的有效類型]。[圖 10 顯示完整 ActionResult 衍生型別的清單。

[圖 10 ActionResult 衍生型別
名稱 Framework 行為 產生方法
ContentResult 您可以將字串值直接將 HTTP 回應。 內容
EmptyResult 不會寫入 HTTP 回應。  
FileContentResult 會在檔案 (表示為位元組陣列) 的內容,並將內容寫入為 HTTP 回應。 檔案
FilePathResult 在指定的位置會在檔案的內容,並寫入 HTTP 回應的內容]。 檔案
FileStreamResult 接受控制器所產生檔案資料流,並寫入 HTTP 回應的資料流中。 檔案
HttpUnauthorizedResult 授權檢查失敗時,授權篩選器會使用一個特殊的結果。  
JavaScriptResult 回應用戶端使用用戶端執行指令碼。 JavaScript
JsonResult 回應用戶端 JavaScript Object Notation (JSON) 資料。 json
RedirectResult 重新導向至新的 URL 的用戶端。 重新導向
RedirectToRouteResult 呈現指定的檢視 (通常是在 AJAX 的案例中使用) 的 HTML 片段的回應。 RedirectToRoute / RedirectToAction
PartialViewResult 呈現指定的檢視 (通常是在 AJAX 的案例中使用) 的 HTML 片段的回應。 PartialView
ViewResult 呈現指定的檢視,並以 HTML 用戶端回應。 檢視

請注意在控制器的動作不會需要直接具現化其中一種型別。而,控制器的動作可以叫用方法的名稱以 [圖 10] 顯示,產生的結果。這些方法被繼承自 MVC 控制器的基底類別中。也是值得注意不需要在控制器的動作傳回 ActionResult 物件。如果控制器可傳回以外的 ActionResult,Framework 會將物件轉換成字串,並包裝在 ContentResult (這只是將字串寫入 HTTP 回應到) 字串。一個控制站傳回 void,就會產生一個 EmptyResult。

ActionResult 類別定義 ExecuteResult 方法每個 [圖 10 ] 中的型別將會覆寫。這個的方法,ControllerActionInvoker 由叫用 (相同的物件,呼叫控制器的動作。叫用 (Invoke),每個搜尋結果會格外謹慎的成功地傳送到 [用戶端的結果所需的所有小細節。例如,JavaScript 結果在 [HttpUnauthorizedResult 將設定,在 401 (未授權) 回應的 HTTP 狀態碼時,會設定"application / x-javascript",回應的內容類型標頭。

在一般的回應,從一個控制器的動作將會是一個 ViewResult。您已經知道這個結果,先前的程式碼清單中,所有您的動作已叫用控制站的檢視方法,並傳回結果。這會是 「 使用慣例,透過組態,」 的另一個範例,因為在 ViewResult 會使用此預設值的方式時尋找一個檢視,請在控制站的檢視資料夾中,並以符合該動作的檔案名稱。舉例來說,views\home\about.aspx 是傳統檢視,需主控制器的動作。多載的版本,檢視方法的可讓您以明確地在檢視的名稱。

在動作是透過

這個月,我已經採取深入探討的抽象概念,並行為周圍的 ASP.NET MVC 控制站。yo u 現在應該已在良好的 MVC) 架構的發現如何掌握、 建立,並使用控制器,以及如何連結到圍繞控制站 MVC) 架構擴充性點。在這個資料行的下一版,我就看方針] 和 [將這些控制站在實際的應用程式中運作的最佳作法。

了解: Helper 方法

如果您覺得奇怪第一次出現在.Framework 時,使用 Helper 方法動作的結果 (view()、 content()),您可能會想要知道如何所有相關且背後的特定的設計決策是。

Helper 方法,傳回動作的結果的後面,本文也,是 99%的 MVC 開發人員的時間撰寫 MVC 應用程式即將要花撰寫控制器的動作。我們想要確定一般的方法是在初始狀態、 可讀取,和盡為宣告。

例如上,您仍然可以撰寫一個動作的方法就像這樣:

public ActionResult Foo {
    // ... do stuff ...
    ViewData.Model = myModel;
    return new ViewResult {ViewName = "Foo", ViewData = this.ViewData};
}

我們要清除這一點,讓我們做了一些的調整,您可以看到:

public ActionResult Foo {
    // ... do stuff ...
    return new View(myModel);
}

這是語言的多的宣告式的方法,(儘管使用非常重要)。 當您讀取該動作的方法時, 它會反映您的目的。 " 我要傳回檢視,其中包含這個模型 」。

--Phil Haak,資深程式管理員是 Microsoft

您問題或意見寄至 xtrmasp@Microsoft.com.

K Scott Allen 是 Pluralsight 的技術人員的成員 OdeToCode 的創始者。 您可以與 Scott 在 Scott@OdeToCode.com 或讀取在他的部落格 odetocode.com/blogs/Scott.