Controller做爲持久層和展示層的橋樑, 封裝了應用程序的邏輯,是MVC中的核心組件之一。html
本篇文章咱們就來談談 Controller, 主要討論兩個方面:web
咱們本身要實現一個控制器有兩種方法:
一種是繼承IController接口,一種是繼承Controller或ControllerBase.
Controller繼承了ControllerBase, 另外Controller和ControllerBase自己也繼承了IController,總之須要實現IController接口.
首先咱們到XEngine中隨便打開一個Controller, 例如AccountController,
能夠看到新建Controller時,腳手架幫咱們繼承了Controller類
瀏覽器
咱們逐級查看,以下幾張圖,右鍵 轉到Controller定義--> 查看ControllerBase定義 --> 查看IController定義,能夠看到Controller須要實現IController中Execute方法。
mvc
接下來,咱們就新建一個類MyCustomController,繼承IController接口,實現Execute方法。框架
namespace XEngine.Web.Controllers { public class MyCustomController:IController { public void Execute(RequestContext requestContext) { requestContext.HttpContext.Response.Write("Hello world."); } } }
運行http://localhost/XEngine/mycustom,能夠看到瀏覽器輸出了Hello world.ide
MVC框架將實現IController接口的類看成一個控制器,根據路由規則將請求發送給它。
上例中,咱們使用到了RequestContext的HttpContext屬性,該屬性用來獲取有關HTTP請求的信息。
RequestContext另外還有一個屬性RouteData,用來獲取請求路由的信息,例如能夠經過以下方式能夠得到controller和action的名稱:
requestContext.RouteData.Values["controller"].ToString();
requestContext.RouteData.Values["action"].ToString();
實現IController接口的控制器須要負責處理請求的各個方面,包括生成對客戶端的響應。
實際應用中咱們像腳手架同樣直接繼承System.Web.Mvc.Controller就能夠了,這種方式咱們就不須要本身實現Execute方法來輸出內容了,能夠經過MVC Framework的action results來解決這個問題。
咱們先舉個例子,看看咱們原來一直使用的ActionReslut生成響應的方式,例如post
public ActionResult NativeOutput() { return Redirect("~/Account/Login"); }
Action 方法不直接使用Response對象,而是返回ActionResult類型的對象。ActionResult類描述了response的類型,好比返回一個view或跳轉到另一個頁面。
當MVC Framework從一個action方法接收一個ActionResult對象時,會調用那個對象的ExecuteResult方法。學習
namespace System.Web.Mvc { // 摘要: // 表示操做方法的結果。 public abstract class ActionResult { // 摘要: // 初始化 System.Web.Mvc.ActionResult 類的新實例。 protected ActionResult(); // 摘要: // 經過從 System.Web.Mvc.ActionResult 類繼承的自定義類型,啓用對操做方法結果的處理。 // // 參數: // context: // 用於執行結果的上下文。上下文信息包括控制器、HTTP 內容、請求上下文和路由數據。 public abstract void ExecuteResult(ControllerContext context); } }
咱們經過一個自定義的ActionResult實現來演示工做機制, 模擬實現這個簡單的跳轉功能, ExecuteResult實現以下:spa
namespace XEngine.Web.Utility { public class CustomRedirectResult:ActionResult { public string Url { get; set; } public override void ExecuteResult(ControllerContext context) { string fullUrl = UrlHelper.GenerateContentUrl(Url, context.HttpContext); context.HttpContext.Response.Redirect(fullUrl); } } }
在Controller中使用code
public CustomRedirectResult CustomOutput() { return new CustomRedirectResult { Url = "~/Account/Login" }; }
能夠看到,實現了一樣的效果。
相似於咱們實現的CustomRedirectResult,MVC框架包含一些內置的action result類型,全部這些類型都繼承於ActionReslut類型。以下列表:
https://msdn.microsoft.com/en-us/library/system.web.mvc.actionresult.aspx
咱們具體使用時能夠明確指明返回類型,如
public ViewResult xxx() { xxx }
或統一返回 ActionResult, 如
public ActionResult xxx() { xxx }
通常我都是籠統的返回 ActionResult,這樣比較方便。(另外具體實現時,一個Action也可能根據不一樣狀況返回不一樣種類的ActionResult,沒辦法明確返回類型)
上面這張表格, HttpStatusCodeResult、 HttpUnauthorizedResult、 EmptyResult這三個Action Result是沒有Helper Method的.
相似於咱們自定義的CustomRedirectResult,使用時須要使用字面量來明確返回結果。下面看例子:
可使用HttpStatusCodeResult 類將一個特定的HTTP狀態碼發送給瀏覽器。下面看下HttpStatusCodeResult的例子,返回特定的HTTP結果碼:
這個類沒有具體的控制器輔助方法,所以必須對這個類進行實例化。
public HttpStatusCodeResult StatusCode() { return new HttpStatusCodeResult(404, "URL cannot beserviced"); }
401和404是HttpStatusCodeResult的兩個特例:
可使用HttpNotFoundResult類取得上面的404效果
public HttpStatusCodeResult NotFoundStatusCode() { return HttpNotFound(); }
發送401結果,一般是把用戶重定向到認證頁面
public HttpStatusCodeResult UnauthorizedStatusCode() { return new HttpUnauthorizedResult(); }
能夠看到,運行後跳轉到認證頁面
咱們討論下一話題:MVC中經常使用的傳遞數據方式。(傳統的Session, Cookie傳遞方式還能夠繼續用,就再也不作介紹了)
咱們使用到的數據傳遞主要有 view到controller, controller到view, 跨view間的數據傳遞三種。下面咱們分別加以說明。
Controller 常常須要訪問來自輸入請求的數據,如查詢字符串值、表單值,以及路由系統根據輸入URL解析所獲得的參數。訪問這些數據有兩個主要途徑:
一、經過context(和ASP.NET 以前版本的技術相似,如咱們熟悉的Request)
二、經過action方法的參數(包括模型綁定),(MVC框架自動檢查上下文給這些參數賦值)
這兩個方式都很經常使用,咱們來依次講解。
當咱們經過繼承ControllerBase類建立controller時, 咱們能夠利用context對象的一組屬性來獲取請求的相關信息, 如Request, Response, RouteData, HttpContext和Server.
經常使用的概括以下表:
這些使用方法有些以前的文章已經介紹過,其餘的在用到時再介紹,就不重複說明了。
經過參數的方法可讀性更好。
以下的重寫例子,咱們先用context讀取表單值,再改寫成參數方式讀取。
先定義一個View
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>GetDataFromView</title> </head> <body> <h1>@ViewBag.Name</h1> <form method="post" > <input name="name" value="Tony"/> <input type="submit" value="提交表單" /> </form> </body> </html>
經過context讀取
public ActionResult GetDataFromView() { ViewBag.Name = Request.Form["name"]; return View(); }
改爲經過參數讀取
public ActionResult GetDataFromView(string name) { ViewBag.Name = name; return View(); }
點擊按鈕後,均返回以下頁面:
經過自動檢查上下文對象和屬性,MVC框架會給action method 參數提供值,這些對象包括Request.QueryString, Request.Form 和 RouteData.Values
模型綁定是MVC推薦的方式,我的感受可使代碼更加乾淨。原理是經過Value Provider Model Binder 兩個組件。
有一組內建的 Value Provider,它們會抓取Request.Form, Request.QueryString, Request.Files以及 RouteData.Values的數據項,而後將這些值傳遞給Model Binder,嘗試將這些數據映射爲action method參數的數據類型。
固然參數也能夠是一個model, 這種方式前面文章已經使用屢次,再也不重複舉例。
直接將對象做爲View的參數便可(即傳遞一個view model object)。
public ActionResult DateOutput() { DateTime date = DateTime.Now; return View(date); }
在View中使用Model關鍵字來訪問 @{ ViewBag.Title = "Index"; } <h2> DateOutput </h2> The day is: @(((DateTime)Model).DayOfWeek)
這種視圖是無類型視圖。該視圖不知道關於視圖模型的任何狀況,而把它做爲object的一個實例來看待。
能夠經過建立強類型視圖來明確model類型,在強類型視圖中包含視圖模型對象類型的詳細信息。
@model DateTime @{ ViewBag.Title = "Index"; } <h2>DateOutput</h2> The day is: @Model.DayOfWeek
注意:指定模型類型是須要小寫的 m, 讀取時用大寫的 M
以前也用過屢次,再也不贅述。
我的認爲ViewBag最大的一個優勢是它便於將多個對象發送給視圖。
前面兩種請求方式都在一輪請求應答中。
還有一種跨請求的狀況,例如重定向致使瀏覽器遞交新的HTTP請求。
若是須要將一個請求的數據傳遞到下一個請求,這種狀況可使用TempData.
使用時直接按Session同樣的語法就能夠了。
TempData和Session的區別是,當讀取TempData值時,值就會被標記爲待刪除,
當請求結束後就會被刪除。
有兩個小技巧:
一、利用Peek方法,能夠獲得TempData的值,而不把它標記爲刪除
DateTime time = (DateTime)TempData.Peek("Date");
二、利用Keep方法,能夠保留一個將被刪除的值
TempData.Keep("Date");
Keep方法不會永久保護一個值。若是這個值被再次讀取,它將被再次標記爲刪除。
關於Controller須要瞭解經常使用的ActionResult類型,掌握數據的傳遞的幾種方式。 歡迎你們多多評論,祝 學習進步:)