深入理解ASP.NET MVC(6)

來源:互聯網
上載者:User

系列目錄

Action全域觀

在上一篇最後,我們進行到了Action調用的“門口”:

if (!ActionInvoker.InvokeAction(ControllerContext, actionName))

在深入研究調用過程的細節前,先有一個總體的認識是很有協助的。InvokeAction方法大致是按照這樣的順序進行的:

 

尋找action:MVC內部尋找action的方法似乎有點複雜,涉及到一個ActionDescriptor的東西,但是原理上是通過反射,在以後的文章中會有所涉及。

驗證和過濾:眾所周知的IActionFilterIAuthorizationFilter在這部分生效,它們在真正執行action之前,事實上對於IResultFilterIExceptionFilter這樣的過濾器是在action執行之後執行的,圖中對於這個沒有畫出。

執行action:真正進入使用者代碼執行,通過反射調用,調用之前還涉及到複雜的參數提供和綁定,在以後的文章中會涉及。

執行結果:ActionResult在這部起到了關鍵的作用,ActionResult有多個派生,其中最為常見的就是ViewResult。ActionResult是前面步驟執行的最終“果實”,通過執行ActionResult的ExecuteResult抽象方法,一個HttpRespose被正確的構造好,準備傳回用戶端。

 

從ActionResult開始說起

就像上一篇講到的,我們可以在ControllerExecute方法中直接對HttpContext.Response操作,繞過action;即便我們走了action這一路,仍然可以在action中像下面這樣直接操作Response:

public class SimpleController : Controller {     public void MyActionMethod()     {         Response.Write("I'll never stop using the <blink>blink</blink> tag");         // ... or ...         Response.Redirect("/Some/Other/Url");         // ... or ...         Response.TransmitFile(@"c:\files\somefile.zip");     } }

然而這種方式難以維護,而且難以單元測試,於是MVC架構建議action返回ActionResult,並由架構調用ActionResultExecuteResult方法,這類似於設計模式中的command模式。你會看到這種設計模式在這裡的運用實在是十分精闢的。

ActionResult是一個十足的抽象類別,抽象到不能再抽象了,它定義了唯一的ExecuteResult方法,參數為一個ControllerContext,其中封裝了包括HttpContext在內的許多個物件,也是重寫這個方法唯一的上下文資訊:

namespace System.Web.Mvc {    public abstract class ActionResult {        public abstract void ExecuteResult(ControllerContext context);    }}

MVC內建了很多實用的ActionResult,如:

我們可以看個簡單的實作類別RedirectResult是如何?ExecuteResult的。在這裡我發現了我曾經遇到過的一個異常的原因:Child actions are not allowed to perform redirect actions,意思是在子action不允許重新導向。

public override void ExecuteResult(ControllerContext context) {    if (context == null) {        throw new ArgumentNullException("context");    }    if (context.IsChildAction) {        throw new InvalidOperationException(MvcResources.RedirectAction_CannotRedirectInChildAction);    }    string destinationUrl = UrlHelper.GenerateContentUrl(Url, context.HttpContext);    context.Controller.TempData.Keep();    context.HttpContext.Response.Redirect(destinationUrl, false /* endResponse */);}

在這段代碼中ExecuteResult的實現相對簡單的多,事實上像ViewResult的實現就複雜很多,關於ViewResult將在視圖中涉及到。

在Controller中有很多輔助方法便於我們在action中返回需要的ActionResult,下面列出:

Content():返回ContentResult

大家都很少用到這個ActionResult,因為它的基本用法是返迴文本,也許下面這段代碼可以說服你

public ContentResult RSSFeed() {     Story[] stories = GetAllStories(); // Fetch them from the database or wherever      // Build the RSS feed document     string encoding = Response.ContentEncoding.WebName;     XDocument rss = new XDocument(new XDeclaration("1.0", encoding, "yes"),         new XElement("rss", new XAttribute("version", "2.0"),             new XElement("channel", new XElement("title", "Example RSS 2.0 feed"),                 from story in stories                 select new XElement("item",                       new XElement("title", story.Title),                       new XElement("description", story.Description),                       new XElement("link", story.Url)                    )             )         )     );      return Content(rss.ToString(), "application/rss+xml"); }

上面的代碼返回了一個RSS。值得注意的是,Content的第二個參數是個contentType(MIME類型,參見www.iana.org/assignments/media-types),如果不指定這個參數將使用text/html的contentType。

事實上我們的action可以返回一個非ActionResult,MVC在執行action的返回結果前,會確保將傳回值轉換成一個ActionResult,其中一步,就是對非空和非ActionResult的結果轉換成string,並封裝成ContentResult:

protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue) {    if (actionReturnValue == null) {        return new EmptyResult();    }    ActionResult actionResult = (actionReturnValue as ActionResult) ??        new ContentResult { Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture) };    return actionResult;}

 

Json():返回JsonResult

Controller的Json方法能返回一個JsonResult,出於安全性的考慮JsonResult只支援POST方式,設定response.ContentType = "application/json";並利用JavaScriptSerializer序列化對象,並返回給用戶端。像下面這樣使用JsonResult:

class CityData { public string city; public int temperature; }  [HttpPost] public JsonResult WeatherData() {     var citiesArray = new[] {         new CityData { city = "London", temperature = 68 },         new CityData { city = "Hong Kong", temperature = 84 }     };      return Json(citiesArray); }
JavaScript():返回JavaScriptResult

JavaScript方法執行個體化一個JavaScriptResult,JavaScriptResult只是簡單的設定response.ContentType = "application/x-javascript";

 

File():返回位元據或檔案

FileResult是個抽象類別,File方法的多個重載返回不同的FileResult:

FilePathResult:直接將一個檔案發送給用戶端

public FilePathResult DownloadReport() {     string filename = @"c:\files\somefile.pdf";     return File(filename, "application/pdf", "AnnualReport.pdf"); }

FileContentResult:返回byte位元組給用戶端比片

public FileContentResult GetImage(int productId) {     var product = productsRepository.Products.First(x => x.ProductID == productId);     return File(product.ImageData, product.ImageMimeType); }
<img src="<%: Url.Action("GetImage", "Products",  new { Model.ProductID }) %>" />

FileStreamResult:返迴流

public FileStreamResult ProxyExampleDotCom() {     WebClient wc = new WebClient();     Stream stream = wc.OpenRead("http://www.example.com/");     return File(stream, "text/html"); }

 

PartialView()和View():分別返回PartialViewResult和ViewResult

PartialViewResult和ViewResult十分複雜,涉及到視圖,將在以後詳細討論。

 

Redirect():返回RedirectResult

產生重新導向結果,上面已經展示了RedirectResult的實現了。

 

RedirectToAction(),RedirectToRoute():返回RedirectToRouteResult

RedirectToRouteResult同樣是產生跳轉的結果,但是它具有“路由表遍曆能力”,也就是具有Url outbound的特點,參見深入理解ASP.NET MVC(3)

 

更多關於ActionResult的衍生類別的細節,可以參看MVC源碼檔案。

勞動果實,轉載請註明出處:http://www.cnblogs.com/P_Chou/archive/2010/11/26/details-asp-net-mvc-06.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.