1. 程式人生 > >瞭解ASP.NET MVC幾種ActionResult的本質:EmptyResult & ContentResult

瞭解ASP.NET MVC幾種ActionResult的本質:EmptyResult & ContentResult

定義在Controller中的Action方法大都返回一個ActionResult物件。ActionResult是對Action執行結果的封裝,用於最終對請求進行響應。ASP.NET MVC提供了一系列的ActionResult,它們本質上是通過怎樣的方式來響應請求的呢?這是這個系列著重討論的主題。[本文已經同步到《How ASP.NET MVC Works?》中]

目錄
一、ActionResult對請求的響應
二、EmptyResult
三、ContentResult
四、例項演示:執行返回型別為非ActionResult的Action方法得到的ActionResult物件
五、例項演示:通過ContentResult實現主題定製

一、ActionResult對請求的響應

HTTP是一個單純的採用請求/回覆訊息交換模式的網路協議,Web伺服器在接收並處理來自客戶端的請求後會根據處理結果對請求予以響應。對於來自客戶端的訪問請求,最終的處理體現在針對目標Action方法的執行,我們可以在定義Action方法的時候人為地控制對請求的響應。如果下面的程式碼片斷所示,抽象類Controller具有一個只讀的Response屬性表示當前的HttpResponse,我們可以直接利用它來實現對請求的響應。我們也可以間接地通過表示當前HTTP上下文的HttpContext屬性和表示Controller上下文的ControllerContext屬性來獲取用於響應請求的HttpResponse物件。

   1: public abstract class Controller : ControllerBase, ...
   2: {
   3:     //其他成員
   4:     public HttpResponseBase     Response { get; }
   5:     public HttpContextBase     HttpContext { get; }
   6: }
   7:  
   8: public abstract
class ControllerBase : IController
   9: {
  10:     //其他成員
  11:     public ControllerContext ControllerContext { get; set; }
  12: }

原則上講,我們可以利用HttpResponse對請求響應作百分之一百地控制,但是我們一般並不這麼做,而是將針對請求的響應實現在一個ActionResult物件中。如下面的程式碼片斷所示,ActionResult是一個抽象型別,最終的請求響應實現在抽象方法ExecuteResult方法中。

   1: public abstract class ActionResult
   2: {    
   3:     //其他成員
   4:     public abstract void ExecuteResult(ControllerContext context);
   5: }

顧名思義,ActionResult就是執行Action的結果。ActionInvoker在完成對Action方法的執行後,如果返回一個ActionResult物件,ActionInvoker會將當前Controller上下文作為引數呼叫其ExecuteResult方法。View的最終呈現是通過ActionResult的子類ViewResult來完成的,除了ViewResult,ASP.NET MVC還為我們定義了額外一些具體的ActionResult。

二、EmptyResult

上面我們談到Action方法返回的ActionResult物件被ActionInvoker呼叫以實現對當前請求的響應,其實這種說法不夠準確。不論Action方法是否具有返回值,也不論它的返回值是什麼型別,ActionInvoker最終都會建立相應的ActionResult物件。如果Action方法返回型別為void,或者返回值為Null,最終生成的就是一個EmptyResult物件。

如下面的程式碼片斷所示,在重寫的ExecuteResult方法中EmptyResult其實什麼都沒有做,所以EmptyResult是一個“空”的ActionResult。EmptyResult的設計體現了一種設計思想:我們採用一種管道式的設計來完成針對某類請求的處理,比如ASP.NET MVC針對請求的處理流程是“Action方法的執行=〉根據執行結果生成ActionResult=〉執行ActionResult”,但是這個流程不適合某些特殊的請求(比如Action方法不具有返回值或者返回值為Null,那麼後面的兩個環節可以忽略),我們對這些例外的場景進行一些適配工作使我們可以按照統一的方式來處理所有的請求,所以EmptyResult在這裡起到了一個介面卡的作用。

   1: public class EmptyResult : ActionResult
   2: {    
   3:     public override void ExecuteResult(ControllerContext context)
   4:     {
   5:     }
   6: }

三、ContentResult

ContentResult使ASP.NET MVC按照我們指定的內容對請求予以響應。如下面的程式碼片斷所示,我們可以利用ContentResult的Content屬性以字串的形式指定響應的內容,另外兩個屬性ContentEncoding和ContentType則用於指定字元編碼方式和媒體型別(MIME型別)。抽象類Controller定義瞭如下三個受保護的Content方法過載根據指定的內容、編碼和媒體型別建立相應的ContentResult。

   1: public class ContentResult : ActionResult
   2: {
   3:     public override void ExecuteResult(ControllerContext context);
   4:     
   5:     public string     Content { get; set; }
   6:     public Encoding   ContentEncoding { get; set; }
   7:     public string     ContentType { get; set; }
   8: }
   9:  
  10: public abstract class Controller : ControllerBase, ...
  11: {
  12:     //其他成員
  13:     protected ContentResult Content(string content);   
  14:     protected ContentResult Content(string content, string contentType);   
  15:     protected virtual ContentResult Content(string content, string contentType, Encoding contentEncoding);
  16: }

在重寫的ExecuteResult方法中,ContentResult利用作為引數的ControllerContext物件得到當前HttpContext的HttpResponse物件,並藉助它將指定的內容按照希望的編碼和媒體型別對請求進行響應,具體的實現如下面的程式碼片斷所示。

   1: public class ContentResult : ActionResult
   2: {
   3:     //其他成員
   4:     public override void ExecuteResult(ControllerContext context)
   5:     {       
   6:         HttpResponseBase response = context.HttpContext.Response;
   7:         if (!string.IsNullOrEmpty(this.ContentType))
   8:         {
   9:             response.ContentType = this.ContentType;
  10:         }
  11:         if (this.ContentEncoding != null)
  12:         {
  13:             response.ContentEncoding = this.ContentEncoding;
  14:         }
  15:         if (this.Content != null)
  16:         {
  17:             response.Write(this.Content);
  18:         }
  19:     }
  20: }

上面我們說過,ASP.NET MVC為了能夠採用相同的流程來處理所有的請求,不論是Action是否具有返回值,具有怎樣的返回值,ActionInvoker都會建立相應的ActionResult。對於不具有返回值或者返回Null的Action方法呼叫來說,最終建立的是一個EmptyResult物件,那麼如果返回值不是一個ActionResult物件,ActionInvoker最終會建立怎樣一個ActionResult物件呢

實際上對於一個非Null的返回值,ActionInvoker採用這樣的方式來建立相應的ActionResult:如果返回物件是一個ActionResult,直接返回該物件,否則將物件轉換成字串並以此建立一個ContentResult物件。ControllerActionInvoker根據Action方法的返回指生成相應ActionResult的邏輯體現在如下一個受保護的虛方法CreateActionResult中,最後一個引數(actionReturnValue)表示Action方法的返回值。而另一個受保護的InvokeActionMethod負責執行Action方法並返回響應的ActionResult物件,該方法在執行Action方法得到返回值後通過呼叫CreateActionResult方法返回相應的ActionResult物件。

   1: public class ControllerActionInvoker : IActionInvoker
   2: {
   3:     //其他成員
   4:     protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters);
   5:     protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue);
   6: }

四、例項演示:執行返回型別為非ActionResult的Action方法得到的ActionResult物件

我們可以通過一個簡單的例項來驗證ActionInvoker針對Action方法返回值對ActionResult的建立邏輯。在一個ASP.NET MVC應用中我們定義瞭如下一個HomeController,其中定義了4個無引數的Action方法。Foo返回一個RedirectResult物件,Bar的返回型別為viod,Baz返回值為Null,而Qux則返回一個double型別的數字。

   1: public class HomeController : Controller
   2: {
   3:     //其他成員
   4:     public ActionResult Foo()
   5:     {
   6:         return new RedirectResult("http://www.asp.net");
   7:     }
   8:     public void Bar(){ }
   9:     public ActionResult Baz()
  10:     {
  11:         return null;
  12:     }
  13:     public double Qux()
  14:     {
  15:         return 1.00;
  16:     }
  17: }

然後我們在HomeController定義如下一個Action方法Index。在該方法中我們通過反射的方式呼叫ActionInvoker的GetControllerDescriptor方法得到用於描述當前Controller的ControllerDescriptor物件。然後呼叫ControllerDescriptor的FindAction方法得到用於描述上述四個Action的ActionDescriptor物件。最後我們同樣採用反射的方式呼叫ActionInvoker的InvokeActionMethod方法執行這4個Action並得到4個ActionResult物件。我們將4個得到ActionResult連同對應的ActionDescriptor物件構建一個Dictionary<ActionDescriptor, ActionResult>物件,並作為Model呈現在預設的View中。

   1: public class HomeController : Controller
   2: {
   3:     //其他成員
   4:     public ActionResult Index()
   5:     {
   6:         Dictionary<ActionDescriptor, ActionResult> actionResults = new Dictionary<ActionDescriptor, ActionResult>();
   7:         MethodInfo getControllerDescriptor = this.ActionInvoker.GetType().GetMethod("GetControllerDescriptor", BindingFlags.Instance | BindingFlags.NonPublic);
   8:         ControllerDescriptor controllerDescriptor = (ControllerDescriptor)getControllerDescriptor.Invoke(this.ActionInvoker, new object[] { ControllerContext });
   9:         MethodInfo invokeActionMethod = this.ActionInvoker.GetType().GetMethod("InvokeActionMethod", BindingFlags.Instance | BindingFlags.NonPublic);
  10:  
  11:         string[] actions = new string[] { "Foo", "Bar", "Baz", "Qux" };
  12:         Array.ForEach(actions, action =>
  13:             {
  14:                 ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(ControllerContext, action);
  15:                 ActionResult actionResult = (ActionResult)invokeActionMethod.Invoke(this.ActionInvoker, new object[] { ControllerContext, actionDescriptor, new Dictionary<string, object>() });
  16:                 actionResults.Add(actionDescriptor, actionResult);
  17:             });
  18:         return View(actionResults);
  19:     }
            
           

相關推薦

瞭解ASP.NET MVCActionResult本質EmptyResult & ContentResult

定義在Controller中的Action方法大都返回一個ActionResult物件。ActionResult是對Action執行結果的封裝,用於最終對請求進行響應。ASP.NET MVC提供了一系列的ActionResult,它們本質上是通過怎樣的方式來響應請求的呢?這是這個系列著重討論的主題。[

瞭解ASP.NET MVCActionResult本質FileResult

FileResult是一個基於檔案的ActionResult,利用FileResult我們可以很容易地將從某個物理檔案的內容響應給客戶端。ASP.NET MVC定義了三個具體的FileResult,分別是FileContentResult、FilePathResult和FileStreamResult。在這篇

瞭解ASP.NET MVCActionResult本質JavaScriptResult & JsonResult

在之前的兩篇文章(《EmptyResult & ContentResult》和《FileResult》)我們剖析了EmptyResult、ContentResult和FileResult這三種ActionResult是如何將Action執行的結果響應給客戶端的。本篇文章著重介紹在進行Ajax呼叫中經常

瞭解ASP.NET MVCActionResult本質HttpStatusCodeResult & RedirectResult/RedirectToRouteResult

在本系列的最後一篇,我們來討論最後三個ActionResult:HttpStatusCodeResult、RedirectResult和RedirectToRouteResult 。第一個用於實現針對某個HTTP狀態的響應,而後兩個用於實現重定向。至於重定向,又分為“暫時重定向”和“永久重定向”,按照響應狀態

asp.net MVC繫結下拉列表的寫法

今天寫寫在asp.net MVC中幾種繫結下拉列表的寫法。 1.在前端寫死資料: @Html.DropDownListFor(m=>m.Sex,new SelectList(new List&l

MVC學習系列-WebForm與asp.net MVC設計模式區別、MVC設計模式基礎瞭解

ASP.NET 是一個開發框架,用於通過 HTML、CSS、JavaScript 以及伺服器指令碼來構建網頁和網站。ASP.NET 支援三種開發模式:Web Pages、MVC (Model View Controller) 以及 WebForm。下面首先區別比較一下Web

【翻譯】瞭解ASP.NET MVC的HTML助手

作者:Shailendra Chauhan works as Software Analyst at reputed MNC and has more than 5 years of hand over Microsoft .NET technologies. He is a

Asp.net檔案下載方式

C# code ASP.NET檔案下載 //TransmitFile實現下載 protected void Button1_Click(object sender, EventArgs e) { /* 微軟為Response

ASP.NET MVC常用ActionResult

一、定義 MVC中ActionResult是Action的返回結果。ActionResult 有多個派生類,每個子類功能均不同,並不是所有的子類都需要返回檢視View,有些直接返回流,有些返回字串等。ActionResult是一個抽象類,它定義了唯一的ExecuteResult方法,引數為一個C

ASP.NET MVC 提高運行速度的性能優化方法

服務 排隊 等待 谷歌搜索 部署 lan str run 提高 主要介紹ASP.NETMVC 應用提速的六種方法,因為沒有人喜歡等待,所以介紹幾種常用的優化方法。 大家可能會遇到排隊等待,遇到紅燈要等待,開個網頁要等待,等等等。 理所當然,沒有人喜歡等待網頁慢吞吞地加載

asp.net MVC html.ActionLink的參數格式

class cti span 生成 get 傳遞 文字 targe classname 一 Html.ActionLink("linkText","actionName") 該重載的第一個參數是該鏈接要顯示的文字,第二個參數是對應的控制器的方法, 默認控制器為當前頁面的控制

ASP.NET MVC下自定義錯誤頁和展示錯誤頁的方式

提供服務 one url attribute 運行 16px execute 釋放 namespace 在網站運行中,錯誤是不可避免的,錯誤頁的產生也是不可缺少的。 這幾天看了博友的很多文章,自己想總結下我從中學到的和實際中配置的。 首先,需要知道產生錯誤頁的來源,一種

asp.net MVC從後端傳遞資料到前端的資料形式:ViewBag,ViewData,Model

參考:https://blog.csdn.net/xiaouncle/article/details/77825389 在以上文章的基礎上做點相關補充。 1.ViewBag是一個動態欄位,而ViewData是一個字典 首先看後臺程式碼: public ActionResult T

ASP.NET MVC 檔案上傳和檔案下載 以及 檔案下載的方法

1、序言最近專案中需要用到這個功能點,但是網上下載的時候總是出現亂碼。所以趁著這個時間自己整理出了一份,以後需要的時候就直接看自己的部落格就行了。已經測試過:在谷歌、火狐、IE等瀏覽器上都不會出現亂碼問題。2、結果展示2.1、上傳檔案成功介面 2.2、下載檔案成功介面3、上傳

asp.net MVC前臺View頁面向後臺Controller控制器傳遞資料的方式

上一篇文章Asp.Net MVC中的@model與Model講解了後臺控制器如何向前臺頁面傳遞資料,今天就接著為大家講解前臺View頁面向後臺Controller控制器傳遞資料的幾種方式。這幾種方式是我在實際中使用並總結的,如果那個地方說的不對或有不足之處,歡迎各位指出並給

asp.net mvcActionResult

new 特殊 包含 string 工作 json數據 value orm none Web服務器接收到一個客戶端請求以後,會對請求予以相應,而這個響應是通過Response來控制的, 但是在asp.net mvc 裏,這部分的工作是由ActionResult來完成的,

ASP.NET MVC中有四過濾器類型

std tpc min fsm emc 為什麽 lbp yun eal 在ASP.NET MVC中有四種過濾器類型 Action 1、在ASP.NET MVC項目中,新建文件夾Filter,然後新建類MyCustormFilter,繼承自ActionFilterA

如何在asp.net mvc中添加自定義的HTML輔助方法

步驟 gen 其他 generic url linq build mode 擴展方法 很久沒在博客園發表文章了,今天來總結一下如何在asp.net mvc中添加自定義的HTML輔助方法。我們現在設計這麽一個目前,利用自定義的HTML方法來渲染一個普通的img標記。直接進入主

ASP.NET MVC Filters 4默認過濾器的使用【附示例】

rac model 指定 host 會話 決策 蜘蛛 formate 操作性 過濾器(Filters)的出現使得我們可以在ASP.NET MVC程序裏更好的控制瀏覽器請求過來的URL,不是每個請求都會響應內容,只響應特定內容給那些有特定權限的用戶,過濾器理論上有以下功能:

Asp.Net MVC及Web API框架配置會碰到的個問題及解決方案(轉)

erb his 控制 NPU vat types ror 控制器 動手 前言 剛開始創建MVC與Web API的混合項目時,碰到好多問題,今天拿出來跟大家一起分享下。有朋友私信我問項目的分層及文件夾結構在我的第一篇博客中沒說清楚,那麽接下來我就準備從這些文件怎麽分文件夾說起