本節來看一下ASP.NET MVC【View的呈現】的內容,View的呈現是在Action執行以後進行,Action的執行生成一個ActionResult,【View的呈現】的功能就是:經過InvokeActionResult方法對【Action的執行】中生成的ActionResult進行處理。(ActionResult泛指那些繼承自抽象類System.Web.Mvc.ActonResult的類的實例)javascript
爲了會縱觀【View的呈現】在全局中的位置,下面咱們再來回顧下處理請求的整個流程:在此係列開篇的時候介紹了MVC的生命週期 , 對於ASP.NET和ASP.NET MVC,都是將相應的類的方法註冊到HttpApplication事件中,經過事件的依次執行從而完成對請求的處理。而針對MVC,請求是先 通過路由系統,而後由一個MvcHandler來處理的,當請求到來時,執行此MvcHandler的ProcessRequest方法(由於已將 MvcHandler類的ProcessRequest方法註冊到HttpApplication的事件中,因此事件的執行就觸發了此方法),下圖就是一個簡要的執行過程!html
public class ControllerActionInvoker : IActionInvoker { protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) { actionResult.ExecuteResult(controllerContext); } }
整個過程大體通過【Controller的激活】-->【Action的執行】-->【View的呈現】,由上圖可知,【View的呈現】是由ControllerActionInvoker類中的InvokeActionResult方法來觸發的!java
概述中提到,【View的呈現】的功能就是:經過InvokeActionResult方法對【Action的執行】中生成的ActionResult進行處理。即:ActionResult是在【Action的執行】中建立的,建立方式有:git
例、自定義個Action過濾器,當沒有經過時按照過濾器中定義的ActionResult進行View的呈現,具體執行過程下一部分介紹!web
public class MyActionFilter:FilterAttribute,IActionFilter { public void OnActionExecuted(ActionExecutedContext filterContext) { } public void OnActionExecuting(ActionExecutingContext filterContext) { if (filterContext.RouteData.DataTokens["OOK"] != "WuPeiqi") { ContentResult contentResult = new ContentResult(); contentResult.Content = "DataToKens值有誤"; filterContext.Result = contentResult; } } } //將此過濾器應用的Action上,那麼當請求中DataTokens的值不是否是相應的值時,就會用過濾器中的ContentResult對象來進行View的呈現,不然,就是利用Action方法Index中建立的ActionResult進行View的呈現! public class HomeController : Controller { [MyActionFilter] public ActionResult Index() { return Content("正確"); } }
ASP.NET MVC的【View的呈現】其實就是執行ActonResult的ExcuteResult方法!而接下來咱們介紹的就是這個ExcuteResult方法觸發了那些操做!!!在介紹以前咱們先來看看微軟提供了那些ActionResult!(ActionResult泛指那些繼承自System.Web.Mvc.ActionResult的類)
json
public abstract class ActionResult { public abstract void ExecuteResult(ControllerContext context); }
在ASP.NET MVC 的【Action的執行】中建立以上任意一個ActionResult對象,並執行該對象的ExcuteResult方法,從而進行【View的呈現】。這裏的最後一項ViewResult比較特殊,它的處理流程相對複雜,涉及到Razor引擎什麼的,以後詳細介紹!api
下面就來看一些以上ActionResult的源碼,瞭解下【View的呈現】如何實現!數組
一、EmptyResult瀏覽器
public class EmptyResult : ActionResult { private static readonly EmptyResult _singleton = new EmptyResult(); internal static EmptyResult Instance { get { return _singleton; } } public override void ExecuteResult(ControllerContext context) { } }
由EmptyResult源碼可見,其ExecuteReuslt方法什麼都沒作,也就是該ActionReuslt的【View的呈現】部分不作任何操做,那麼此流程也就執行完畢。再看概述中的圖可知,接下來進行【對TempData再一次處理】-->【釋放Controller對象】,以後再繼續HttpApplication其餘的事件,包括對Session的處理、緩存的處理、對請求的返回等。緩存
二、ContentResult
ContentResult用於將字符串響應給客戶端!
public class ContentResult : ActionResult { public string Content { get; set; } public Encoding ContentEncoding { get; set; } public string ContentType { get; set; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } HttpResponseBase response = context.HttpContext.Response; if (!String.IsNullOrEmpty(ContentType)) { response.ContentType = ContentType; } if (ContentEncoding != null) { response.ContentEncoding = ContentEncoding; } if (Content != null) { response.Write(Content); } } }
上述context.HttpContext.Response獲得的是一個HttpResponseWrapper類型的對象response,該對象內有一個HttpResponse類型的私有變量_httpResponse,對於該HttpResponseWrapper對象的屬性和方法其實都是執行私有變量_httpResponse對應的屬性和方法!
因爲HttpResponseWrapper對象屬性和方法都是對私有變量_httpResponse的相關操做,而查看HttpResponseWrapper類部分源代碼,_httpResponse變量是經過構造函數賦值的,而該構造函數的參數值是怎麼來的呢?是在HttpApplication事件以前,經過HttpRuntime類建立請求上下文HttpContext對象時,又觸發建立了HttpResponse對象並賦值到請求上下文HttpContext對象的一個私有變量中保存着的!
又因爲HttpResponse對象的屬性和方法又都是對私有變量_writer的相關操做,再看HttpResponse類的源代碼,它的Write的方法實際上是執行其TextWriter類型的私有變量_writer的Write方法,而該私有變量_writer是怎麼來的呢?是在HttpApplication事件以前,經過HttpRuntime類建立請求上下文HttpContext對象時,觸發建立了HttpResponse對象,以後又初始化HttpResponse對象的_writer字段爲一個HttpWriter對象。
最終,執行HttpWriter對象的Write方法,根據ContentType定義的媒體類型和ContentEncoding定義的編碼方法將字符串發送到 HTTP 輸出流。ContentType定義的是MIME類型(默認爲」text/html"),ContentEncoding定義的編碼方式(默認是操做系統的當前 ANSI 代碼頁的編碼System.Text.Encoding.Default)。
public class HttpResponseWrapper : HttpResponseBase { private HttpResponse _httpResponse; //設置或獲取響應內容的編碼類型 public override Encoding ContentEncoding { get { return this._httpResponse.ContentEncoding; } set { this._httpResponse.ContentEncoding = value; } } public override string ContentType { get { return this._httpResponse.ContentType; } set { this._httpResponse.ContentType = value; } } public override void Write(string s) { this._httpResponse.Write(s); } }
public sealed class HttpResponse { private TextWriter _writer; private Encoding _encoding; private string _contentType = "text/html"; public Encoding ContentEncoding { get { if (this._encoding == null) { //獲取webconfig文件中,globalization節點的值 GlobalizationSection globalization = RuntimeConfig.GetLKGConfig(this._context).Globalization; if (globalization != null) { //設置Http響應的內容編碼 this._encoding = globalization.ResponseEncoding; } //沒有在globalization節點中配置編碼類型 if (this._encoding == null) { //獲取操做系統的當前 ANSI 代碼頁的編碼並賦值給Http響應內容的編碼 this._encoding = Encoding.Default; } } return this._encoding; } set { if (value == null) { throw new ArgumentNullException("value"); } //當沒有設置編碼類型或者編碼類型和原來的不相同時,根據value從新設定編碼類型 if (this._encoding == null || !this._encoding.Equals(value)) { this._encoding = value; this._encoder = null; if (this._httpWriter != null) { //將HttpResponse類中與編碼相關的屬性值賦值到HttpWriter對象中與編碼相關的屬性 //以便HttpWriter輸出響應流時按照此編碼進行 this._httpWriter.UpdateResponseEncoding(); } } } } public string ContentType { get { return this._contentType; } set { if (!this._headersWritten) { this._contentTypeSetByManagedCaller = true; this._contentType = value; return; } if (this._contentType == value) { return; } throw new HttpException(SR.GetString("Cannot_set_content_type_after_headers_sent")); } } public void Write(string s) { this._writer.Write(s); } }
public sealed class HttpWriter : TextWriter { //根據編碼規則將字符串發送到 HTTP 輸出流 public override void Write(string s) { if (this._ignoringFurtherWrites) { return; } if (s == null) { return; } if (s.Length != 0) { if (s.Length < this._charBufferFree) { StringUtil.UnsafeStringCopy(s, 0, this._charBuffer, this._charBufferLength - this._charBufferFree, s.Length); this._charBufferFree -= s.Length; } else { int i = s.Length; int num = 0; while (i > 0) { if (this._charBufferFree == 0) { this.FlushCharBuffer(false); } int num2 = (i < this._charBufferFree) ? i : this._charBufferFree; StringUtil.UnsafeStringCopy(s, num, this._charBuffer, this._charBufferLength - this._charBufferFree, num2); this._charBufferFree -= num2; num += num2; i -= num2; } } } if (!this._responseBufferingOn) { //將信息寫入 HTTP 響應輸出流。 this._response.Flush(); } } //更新編碼相關的字段 internal void UpdateResponseEncoding() { if (this._responseEncodingUpdated && this._charBufferLength != this._charBufferFree) { this.FlushCharBuffer(true); } this._responseEncoding = this._response.ContentEncoding; this._responseEncoder = this._response.ContentEncoder; this._responseCodePage = this._responseEncoding.CodePage; this._responseCodePageIsAsciiCompat = CodePageUtils.IsAsciiCompatibleCodePage(this._responseCodePage); this._responseEncodingUpdated = true; } }
在ASP.NET MVC 的Controller類中提供瞭如下三個建立ContentResult的重載,固然也能夠直接在Action中建立ContentReuslt對象並做爲方法的返回值。
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer { //省略其餘方法 protected internal ContentResult Content(string content) { return Content(content, null /* contentType */); } protected internal ContentResult Content(string content, string contentType) { return Content(content, contentType, null /* contentEncoding */); } protected internal virtual ContentResult Content(string content, string contentType, Encoding contentEncoding) { return new ContentResult { Content = content, ContentType = contentType, ContentEncoding = contentEncoding }; } }
擴展:請求上下文HttpContext、HttpResponse、HttpRequest建立流程
當請求到達IIS,IIS根據請求的後綴名判斷是否加載aspnet_isapi.dll,一旦工做進程加載了aspnet_isapi.dll,就會加載IsapiRuntime,被加載的IsapiRuntime會接管Http請求,以後IsapiRuntime執行其方法ProcessRequest(IntPtr ecb, int iWRType),該方法實現從ISAPI擴展控制塊(ECB)中獲取當前Http請求相關信息並封裝到IsapiWorkrRequest對象中。而後將該對象傳遞給HttpRuntime,經過該類中的ProcessRequestInternal()方法建立HttpContext類實例,進入ProcessRequestInternal方法以後,內部觸發一系列的方法,最終建立一個HttpContent實例(可經過HttpContent.Current獲取到這個實例),且該實例會在整個生命週期內存活。建立HttpContext對象時,同時也建立了HttpRequest和HttpResponse對象,並賦值到私有字段中,經過公有屬性去獲取這兩個對象。
以後HttpRuntime類會向HttpApplicationFactory類 提出請求,要求返回一個HttpApplication對象,HttpApplicationFactory在收到請求以後會檢查是否有已經存在而且空閒的對象,若是有就取出一個HttpApplication對象返回給HttpRuntime類,若是沒有,則要建立一個給HttpRuntime。
public sealed class ISAPIRuntime : MarshalByRefObject, IISAPIRuntime, IISAPIRuntime2, IRegisteredObject { public ISAPIRuntime() { //將該ISAPIRuntime對象放在應用程序的已註冊對象列表中 HostingEnvironment.RegisterObject(this); } public int ProcessRequest(IntPtr ecb, int iWRType) { IntPtr intPtr = IntPtr.Zero; if (iWRType == 2) { intPtr = ecb; ecb = UnsafeNativeMethods.GetEcb(intPtr); } ISAPIWorkerRequest iSAPIWorkerRequest = null; int result; try { bool useOOP = iWRType == 1; //將ISAPI擴展控制塊(ECB)中Http請求相關的信息封裝到IsapiWorkerRequest對象中 iSAPIWorkerRequest = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP); iSAPIWorkerRequest.Initialize(); string appPathTranslated = iSAPIWorkerRequest.GetAppPathTranslated(); string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal; if (appDomainAppPathInternal == null || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal)) { //ASP.NET運行時開始執行 HttpRuntime.ProcessRequestNoDemand(iSAPIWorkerRequest); result = 0; } else { HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString("Hosting_Phys_Path_Changed", new object[] { appDomainAppPathInternal, appPathTranslated })); result = 1; } } //省略部分代碼 return result; } }
public sealed class HttpRuntime { //靜態字段 private static HttpRuntime _theRuntime; public HttpRuntime() { } //靜態構造函數 static HttpRuntime() { HttpRuntime.s_autogenKeys = new byte[1024]; HttpRuntime.DirectorySeparatorString = new string(Path.DirectorySeparatorChar, 1); HttpRuntime.DoubleDirectorySeparatorString = new string(Path.DirectorySeparatorChar, 2); HttpRuntime.s_InvalidPhysicalPathChars = new char[] { '/', '?', '*', '<', '>', '|', '"' }; HttpRuntime.s_initialized = false; HttpRuntime.s_isEngineLoaded = false; HttpRuntime.s_factoryLock = new object(); HttpRuntime.AddAppDomainTraceMessage("*HttpRuntime::cctor"); HttpRuntime.StaticInit(); HttpRuntime._theRuntime = new HttpRuntime(); HttpRuntime._theRuntime.Init(); HttpRuntime.AddAppDomainTraceMessage("HttpRuntime::cctor*"); } internal static void ProcessRequestNoDemand(HttpWorkerRequest wr) { RequestQueue requestQueue = HttpRuntime._theRuntime._requestQueue; wr.UpdateInitialCounters(); if (requestQueue != null) { wr = requestQueue.GetRequestToExecute(wr); } if (wr != null) { HttpRuntime.CalculateWaitTimeAndUpdatePerfCounter(wr); wr.ResetStartTime(); //繼續執行 HttpRuntime.ProcessRequestNow(wr); } } internal static void ProcessRequestNow(HttpWorkerRequest wr) { //繼續執行 HttpRuntime._theRuntime.ProcessRequestInternal(wr); } private void ProcessRequestInternal(HttpWorkerRequest wr) { Interlocked.Increment(ref this._activeRequestCount); if (this._disposingHttpRuntime) { try { wr.SendStatus(503, "Server Too Busy"); wr.SendKnownResponseHeader(12, "text/html; charset=utf-8"); byte[] bytes = Encoding.ASCII.GetBytes("<html><body>Server Too Busy</body></html>"); wr.SendResponseFromMemory(bytes, bytes.Length); wr.FlushResponse(true); wr.EndOfRequest(); } finally { Interlocked.Decrement(ref this._activeRequestCount); } return; } HttpContext httpContext; try { //建立請求上下文,繼續執行 httpContext = new HttpContext(wr, false); } catch { try { wr.SendStatus(400, "Bad Request"); wr.SendKnownResponseHeader(12, "text/html; charset=utf-8"); byte[] bytes2 = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>"); wr.SendResponseFromMemory(bytes2, bytes2.Length); wr.FlushResponse(true); wr.EndOfRequest(); return; } finally { Interlocked.Decrement(ref this._activeRequestCount); } } wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, httpContext); HostingEnvironment.IncrementBusyCount(); try { try { this.EnsureFirstRequestInit(httpContext); } catch { if (!httpContext.Request.IsDebuggingRequest) { throw; } } //初始化HttpResponse的TextWriter httpContext.Response.InitResponseWriter(); //經過 HttpApplicationFactory獲取HttpApplication實例 IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(httpContext); if (applicationInstance == null) { throw new HttpException(SR.GetString("Unable_create_app_object")); } if (EtwTrace.IsTraceEnabled(5, 1)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, httpContext.WorkerRequest, applicationInstance.GetType().FullName, "Start"); } if (applicationInstance is IHttpAsyncHandler) { IHttpAsyncHandler httpAsyncHandler = (IHttpAsyncHandler)applicationInstance; httpContext.AsyncAppHandler = httpAsyncHandler; httpAsyncHandler.BeginProcessRequest(httpContext, this._handlerCompletionCallback, httpContext); } else { applicationInstance.ProcessRequest(httpContext); this.FinishRequest(httpContext.WorkerRequest, httpContext, null); } } catch (Exception e) { httpContext.Response.InitResponseWriter(); this.FinishRequest(wr, httpContext, e); } } }
public sealed class HttpContext : IServiceProvider, IPrincipalContainer { //構造函數 public HttpContext(HttpWorkerRequest wr) { this._wr = wr; //初始化HttpContext並建立HttpRequest和HttpResponse this.Init(new HttpRequest(wr, this), new HttpResponse(wr, this)); //初始化HttpResponse的TextWriter this._response.InitResponseWriter(); } private void Init(HttpRequest request, HttpResponse response) { this._request = request; this._response = response; //省略其餘代碼 } }
三、FileResult
FileResult用於將某個物理文件的內容響應給客戶端!
public abstract class FileResult : ActionResult { private string _fileDownloadName; protected FileResult(string contentType) { if (String.IsNullOrEmpty(contentType)) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "contentType"); } ContentType = contentType; } public string ContentType { get; private set; } public string FileDownloadName { get { return _fileDownloadName ?? String.Empty; } set { _fileDownloadName = value; } } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } HttpResponseBase response = context.HttpContext.Response; //response.ContentType默認爲「text/html」 response.ContentType = ContentType; //若是沒有指定文件被下載的名稱,則按照內聯的方法輸出文件,不然按照附件的形式。 if (!String.IsNullOrEmpty(FileDownloadName)) { //處理文件名 並 構造「Content-Disposition」的報頭的值 //例如:文件名中包含Unicode碼或包含特殊符號等 string headerValue = ContentDispositionUtil.GetHeaderValue(FileDownloadName); //採用附件形式,須要爲響應建立一個名稱爲「Content-Disposition」的報頭,該報頭的值格式爲「attachment;filename={文件名}」 context.HttpContext.Response.AddHeader("Content-Disposition", headerValue); } WriteFile(response); } protected abstract void WriteFile(HttpResponseBase response); //處理文件名並構造 「Content-Disposition」的報頭的值 internal static class ContentDispositionUtil { private const string HexDigits = "0123456789ABCDEF"; private static void AddByteToStringBuilder(byte b, StringBuilder builder) { builder.Append('%'); int i = b; AddHexDigitToStringBuilder(i >> 4, builder); AddHexDigitToStringBuilder(i % 16, builder); } private static void AddHexDigitToStringBuilder(int digit, StringBuilder builder) { builder.Append(HexDigits[digit]); } private static string CreateRfc2231HeaderValue(string filename) { StringBuilder builder = new StringBuilder("attachment; filename*=UTF-8''"); byte[] filenameBytes = Encoding.UTF8.GetBytes(filename); foreach (byte b in filenameBytes) { if (IsByteValidHeaderValueCharacter(b)) { builder.Append((char)b); } else { AddByteToStringBuilder(b, builder); } } return builder.ToString(); } public static string GetHeaderValue(string fileName) { // If fileName contains any Unicode characters, encode according // to RFC 2231 (with clarifications from RFC 5987) foreach (char c in fileName) { if ((int)c > 127) { return CreateRfc2231HeaderValue(fileName); } } // Knowing there are no Unicode characters in this fileName, rely on // ContentDisposition.ToString() to encode properly. // In .Net 4.0, ContentDisposition.ToString() throws FormatException if // the file name contains Unicode characters. // In .Net 4.5, ContentDisposition.ToString() no longer throws FormatException // if it contains Unicode, and it will not encode Unicode as we require here. // The Unicode test above is identical to the 4.0 FormatException test, // allowing this helper to give the same results in 4.0 and 4.5. ContentDisposition disposition = new ContentDisposition() { FileName = fileName }; return disposition.ToString(); } // Application of RFC 2231 Encoding to Hypertext Transfer Protocol (HTTP) Header Fields, sec. 3.2 // http://greenbytes.de/tech/webdav/draft-reschke-rfc2231-in-http-latest.html private static bool IsByteValidHeaderValueCharacter(byte b) { if ((byte)'0' <= b && b <= (byte)'9') { return true; // is digit } if ((byte)'a' <= b && b <= (byte)'z') { return true; // lowercase letter } if ((byte)'A' <= b && b <= (byte)'Z') { return true; // uppercase letter } switch (b) { case (byte)'-': case (byte)'.': case (byte)'_': case (byte)'~': case (byte)':': case (byte)'!': case (byte)'$': case (byte)'&': case (byte)'+': return true; } return false; } } }
對於FileResult,具備一個表示媒體類型的只讀屬性ContentType,該屬性在構造函數中被初始化。當咱們基於某個物理文件建立相應的FileReuslt對象的時候應該根據文件的類型指定該媒體類型屬性,例如:目標文件是.jpg圖片,那麼對應的媒體類型應該是「image/jpeg」;對於一個.pdf文件,則採用「application/pdf」。
對於FileResult,還具備一個表示下載文件名的屬性FileDownloadName,若是該屬性沒有指定或者設置的值爲null,則會按照內聯的方式利用瀏覽器直接打開響應的文件,不然會以附件的形式被下載而且文件名爲屬性FileDownloadName的值。(查看FileResult源碼可知,內聯和附件的區別是響應是否包含「Content-Disposition」報頭)
FileReult僅僅是一個抽象類,對於文件內容的輸出實如今抽象方法WriteFile方法中。FileResult有三個派生類實現了WriterFile方法分別是:
public class FileContentResult : FileResult { //參數爲字節數組、響應的媒體類型 public FileContentResult(byte[] fileContents, string contentType) : base(contentType) { if (fileContents == null) { throw new ArgumentNullException("fileContents"); } FileContents = fileContents; } public byte[] FileContents { get; private set; } protected override void WriteFile(HttpResponseBase response) { //將字節數組輸出 response.OutputStream.Write(FileContents, 0, FileContents.Length); } }
public class FileStreamResult : FileResult { // default buffer size as defined in BufferedStream type private const int BufferSize = 0x1000; //參數爲:文件流、媒體類型 public FileStreamResult(Stream fileStream, string contentType) : base(contentType) { if (fileStream == null) { throw new ArgumentNullException("fileStream"); } FileStream = fileStream; } public Stream FileStream { get; private set; } protected override void WriteFile(HttpResponseBase response) { // grab chunks of data and write to the output stream Stream outputStream = response.OutputStream; using (FileStream) { byte[] buffer = new byte[BufferSize]; while (true) { int bytesRead = FileStream.Read(buffer, 0, BufferSize); if (bytesRead == 0) { // no more data break; } outputStream.Write(buffer, 0, bytesRead); } } } }
public class FilePathResult : FileResult { //參數爲:文件路徑、媒體類型 public FilePathResult(string fileName, string contentType) : base(contentType) { if (String.IsNullOrEmpty(fileName)) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "fileName"); } FileName = fileName; } public string FileName { get; private set; } protected override void WriteFile(HttpResponseBase response) { response.TransmitFile(FileName); } }
以上的三個繼承自FileResult的類,最終都是經過 文件的字節數組 的形式發送到Http輸出流,不一樣的是做爲開發者其起始點不一,FileContentResult傳入字節數組而後將內容寫入當前Http響應的輸出流,FileStreamReuslt傳入數據流,以後內部存入字節數組再將內容寫入當前Http響應的輸出流,FilePathResult傳入文件地址,以後內部讀取文件並存入字節數組再將內容寫入當前Http響應的輸出流。
在ASP.NET MVC 的Controller類中提供了建立以上三個FileResult派生類的對象的重載,固然也能夠直接在Action中建立相應的FileReuslt對象並做爲方法的返回值。
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer { protected internal FileContentResult File(byte[] fileContents, string contentType) { return File(fileContents, contentType, null /* fileDownloadName */); } protected internal virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName) { return new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName }; } protected internal FileStreamResult File(Stream fileStream, string contentType) { return File(fileStream, contentType, null /* fileDownloadName */); } protected internal virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName) { return new FileStreamResult(fileStream, contentType) { FileDownloadName = fileDownloadName }; } protected internal FilePathResult File(string fileName, string contentType) { return File(fileName, contentType, null /* fileDownloadName */); } protected internal virtual FilePathResult File(string fileName, string contentType, string fileDownloadName) { return new FilePathResult(fileName, contentType) { FileDownloadName = fileDownloadName }; } }
四、JavaScriptResult
在後臺動態的以字符串形式傳入一段JavaScript腳本,並做爲請求的響應使得腳本在客戶端被執行!
public class JavaScriptResult : ActionResult { public string Script { get; set; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } HttpResponseBase response = context.HttpContext.Response; //指定響應的媒體類型 response.ContentType = "application/x-javascript"; if (Script != null) { response.Write(Script); } } }
經過JavaScriptResult源碼能夠看出,其輸出方式和ContentResult相同,不一樣的只是在JavaScriptResult中內部指定了輸出的媒體類型爲「application/x-javascript」(也能夠是「text/javascript」),而咱們也能夠經過設置ContentResult的輸出媒體類型來實現與JavaScriptResult相同的功能!
在ASP.NET MVC 的Controller類中提供了建立JavaScriptResult對象的方法,固然也能夠直接在Action中建立JavaScriptResult對象並做爲方法的返回值。
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer { //省略其餘代碼 protected internal virtual JavaScriptResult JavaScript(string script) { return new JavaScriptResult { Script = script }; } }
五、JsonResult
JsonResutl用於以Json的格式返回響應的數據!
public class JsonResult : ActionResult { public JsonResult() { //定義枚舉類型,默認拒絕Get請求的響應 JsonRequestBehavior = JsonRequestBehavior.DenyGet; } public Encoding ContentEncoding { get; set; } public string ContentType { get; set; } public object Data { get; set; } //是否決絕Http Get請求(默認拒絕---構造函數中定義) public JsonRequestBehavior JsonRequestBehavior { get; set; } /// <summary> ///指定 JSON 字符串的最大長度(UTF-8 字符的最大數量)。 默認長度爲 102400。 /// </summary> public int? MaxJsonLength { get; set; } /// <summary> /// 指定要序列化類型的最大深度。 默認的遞歸限制爲 100。 /// </summary> public int? RecursionLimit { get; set; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } //若是拒絕Get請求&&發送來的請求也是Get方式 if (JsonRequestBehavior == JsonRequestBehavior.DenyGet && String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException(MvcResources.JsonRequest_GetNotAllowed); } HttpResponseBase response = context.HttpContext.Response; //默認媒體類型爲"application/json" if (!String.IsNullOrEmpty(ContentType)) { response.ContentType = ContentType; } else { response.ContentType = "application/json"; } //編碼類型的選取仍是和ContentResult中同樣,優先級:顯示設定>WebConfig中節點>Encoding.Default if (ContentEncoding != null) { response.ContentEncoding = ContentEncoding; } if (Data != null) { //經過JavaScriptSerializer來將CLR對象序列化成Json格式字符串 JavaScriptSerializer serializer = new JavaScriptSerializer(); if (MaxJsonLength.HasValue) { //serializer.MaxJsonLength是JSON 字符串的最大長度(UTF-8 字符的最大數量)。 默認長度爲 102400 serializer.MaxJsonLength = MaxJsonLength.Value; } if (RecursionLimit.HasValue) { //serializer.RecursionLimit是指要序列化類型的最大深度。 默認的遞歸限制爲 100 serializer.RecursionLimit = RecursionLimit.Value; } //將Json格式的字符串寫入當前Http響應的輸出流 response.Write(serializer.Serialize(Data)); } } }
public enum JsonRequestBehavior { AllowGet, DenyGet, }
對於JsonResult,其構造函數中爲屬性JsonRequestBehavior設置了一個枚舉值DenyGet,該枚舉值的做用就是拒絕對GET請求進行響應,也就是默認狀況下,對於Json格式的數據響應,Get請求是不予支持的。若是想要支持Get請求,能夠顯示的設置JsonRequestBehavior屬性的枚舉值爲AllowGet。
對於JsonResult,其默認的媒體類型爲「application/json」。
JsonResult就是將CLR對象到Json格式字符串的序列化過程,而上述源碼中的object類型的Data屬性就是用來獲取或設置原始的CLR對象,原始的CLR對象經過JavaScriptSerializer類的Serialize方法的序列化,將CLR對象轉換成Json格式的字符串。在JavaScriptSerializer類在對CLR對象進行序列化時還能夠對過程進行一些設置,即:MaxJsonLength(Json字符串的最大長度)、RecursionLimit(序列化類時遞歸的最大深度)。能夠在JsonResult對應的屬性中設置,也能夠在WebConfig中設置。更多設置
<configuration> <system.web.extensions> <scripting> <webServices> <jsonSerialization maxJsonLength="5000"/> </webServices> </scripting> </system.web.extensions> </configuration>
在ASP.NET MVC 的Controller類中提供了一下建立JsonResult對象的方法,固然也能夠直接在Action中建立JsonResult對象並做爲方法的返回值。
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer { //省略其餘代碼 protected internal JsonResult Json(object data) { return Json(data, null /* contentType */, null /* contentEncoding */, JsonRequestBehavior.DenyGet); } protected internal JsonResult Json(object data, string contentType) { return Json(data, contentType, null /* contentEncoding */, JsonRequestBehavior.DenyGet); } protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding) { return Json(data, contentType, contentEncoding, JsonRequestBehavior.DenyGet); } protected internal JsonResult Json(object data, JsonRequestBehavior behavior) { return Json(data, null /* contentType */, null /* contentEncoding */, behavior); } protected internal JsonResult Json(object data, string contentType, JsonRequestBehavior behavior) { return Json(data, contentType, null /* contentEncoding */, behavior); } protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior) { return new JsonResult { Data = data, ContentType = contentType, ContentEncoding = contentEncoding, JsonRequestBehavior = behavior }; } }
六、HttpStatusCodeResult
HttpStatusCodeResult用於返回對Http請求響應狀態的代碼和一個可選的狀態描述!
public class HttpStatusCodeResult : ActionResult { public HttpStatusCodeResult(int statusCode) : this(statusCode, null) { } //HttStatusCode是個枚舉類型,用於定義狀態代碼 public HttpStatusCodeResult(HttpStatusCode statusCode) : this(statusCode, null) { } public HttpStatusCodeResult(HttpStatusCode statusCode, string statusDescription) : this((int)statusCode, statusDescription) { } public HttpStatusCodeResult(int statusCode, string statusDescription) { StatusCode = statusCode; StatusDescription = statusDescription; } //響應狀態代碼 public int StatusCode { get; private set; } //響應狀態描述 public string StatusDescription { get; private set; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } //默認狀態代碼爲:200 context.HttpContext.Response.StatusCode = StatusCode; if (StatusDescription != null) { context.HttpContext.Response.StatusDescription = StatusDescription; } } }
HttpStatusCodeResult爲Http的響應頭設置狀態代碼和狀態描述,設置時,能夠經過構造函數傳入值也能夠經過給屬性賦值來操做。對於HttpStatustCodeResult的構造函數中HttpStatusCode類型的參數,它是一個枚舉類型,其中包含了衆多Http響應頭狀態。
值得一說的是,若是咱們採用Visual StudioDvelopment Server做爲Web應用的宿主,經過HttpStatusCodeResult的StatusDescription屬性設置的狀態描述信息不會反映在Http響應中,只有採用IIS做爲宿主纔會真正將此信息寫入響應消息。
public enum HttpStatusCode { Continue = 100, SwitchingProtocols, OK = 200, Created, Accepted, NonAuthoritativeInformation, NoContent, ResetContent, PartialContent, MultipleChoices = 300, Ambiguous = 300, MovedPermanently, Moved = 301, Found, Redirect = 302, SeeOther, RedirectMethod = 303, NotModified, UseProxy, Unused, TemporaryRedirect, RedirectKeepVerb = 307, BadRequest = 400, Unauthorized, PaymentRequired, Forbidden, NotFound, MethodNotAllowed, NotAcceptable, ProxyAuthenticationRequired, RequestTimeout, Conflict, Gone, LengthRequired, PreconditionFailed, RequestEntityTooLarge, RequestUriTooLong, UnsupportedMediaType, RequestedRangeNotSatisfiable, ExpectationFailed, UpgradeRequired = 426, InternalServerError = 500, NotImplemented, BadGateway, ServiceUnavailable, GatewayTimeout, HttpVersionNotSupported }
ASP.NET MVC中有兩個繼承自HttpStatusCodeResult的類,即:HttpNotFoundResult和AuthorizeAttribute,用於指定特定相應狀態和狀態描述,本質上仍是執行HttpStatusCodeResult來完成,只不過在內部爲HttpStatuCodeResult指定了響應狀態,分別是40四、401。
public class HttpNotFoundResult : HttpStatusCodeResult { public HttpNotFoundResult() : this(null) { } // NotFound is equivalent to HTTP status 404. public HttpNotFoundResult(string statusDescription) : base(HttpStatusCode.NotFound, statusDescription) { } }
public class HttpUnauthorizedResult : HttpStatusCodeResult { public HttpUnauthorizedResult() : this(null) { } // Unauthorized is equivalent to HTTP status 401, the status code for unauthorized // access. Other code might intercept this and perform some special logic. For // example, the FormsAuthenticationModule looks for 401 responses and instead // redirects the user to the login page. public HttpUnauthorizedResult(string statusDescription) : base(HttpStatusCode.Unauthorized, statusDescription) { } }
七、RedirecteResult
RedirectResult用於實現針對某個地址的重定向!
public class RedirectResult : ActionResult { public RedirectResult(string url) : this(url, permanent: false) { } public RedirectResult(string url, bool permanent) { if (String.IsNullOrEmpty(url)) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "url"); } Permanent = permanent; Url = url; } //是否永久重定向,默認爲否。(永久重定向的Http狀態碼爲301,不然是暫時重定向Http狀態碼爲302) public bool Permanent { get; private set; } //要跳轉的地址(相對地址或絕對地址) public string Url { get; private set; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (context.IsChildAction) { throw new InvalidOperationException(MvcResources.RedirectAction_CannotRedirectInChildAction); } //處理Url地址,相對地址的處理。 string destinationUrl = UrlHelper.GenerateContentUrl(Url, context.HttpContext); context.Controller.TempData.Keep(); //是否永久重定向 if (Permanent) { context.HttpContext.Response.RedirectPermanent(destinationUrl, endResponse: false); } else { context.HttpContext.Response.Redirect(destinationUrl, endResponse: false); } } }
對於RedirectResult,能夠定義暫時重定向(302重定向)和永久重定向(301重定向),兩種重定向的不一樣做用主要體如今SEO上,搜索引擎會使用永久重定向目標地址更新本身的索引,而暫時重定向則不會。另外,永久重定向是在ASP.NET 4以後引進的,在以前若是想要實現永久重定向的話,須要本身來設置Http響應狀態碼爲301。
對於UrlHelper.GenerateCotentUrl方法,用來處理Url。當定義的Url爲相對地址時,如:~/xxx/xxx,該方法會利用請求上下文來補全地址。
public static string GenerateContentUrl(string contentPath, HttpContextBase httpContext) { if (string.IsNullOrEmpty(contentPath)) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "contentPath"); } if (httpContext == null) { throw new ArgumentNullException("httpContext"); } if (contentPath[0] == '~') { return PathHelpers.GenerateClientUrl(httpContext, contentPath); } return contentPath; }
對於ASP.NET MVC的Controller類中定義了一下幾個方法來建立RedirectResult,然也能夠直接在Action中建立RedirectResult對象並做爲方法的返回值。
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer { //省略其餘代碼 protected internal virtual RedirectResult Redirect(string url) { if (String.IsNullOrEmpty(url)) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "url"); } return new RedirectResult(url); } protected internal virtual RedirectResult RedirectPermanent(string url) { if (String.IsNullOrEmpty(url)) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "url"); } return new RedirectResult(url, permanent: true); } }
八、RedirectToRoutResult
RedirectToRouteResult用於將路由信息中的Controller和Action拼接成Url,再進行跳轉!
public class RedirectToRouteResult : ActionResult { private RouteCollection _routes; public RedirectToRouteResult(RouteValueDictionary routeValues) : this(null, routeValues) { } public RedirectToRouteResult(string routeName, RouteValueDictionary routeValues) : this(routeName, routeValues, permanent: false) { } public RedirectToRouteResult(string routeName, RouteValueDictionary routeValues, bool permanent) { Permanent = permanent; RouteName = routeName ?? String.Empty; RouteValues = routeValues ?? new RouteValueDictionary(); } public bool Permanent { get; private set; } public string RouteName { get; private set; } public RouteValueDictionary RouteValues { get; private set; } internal RouteCollection Routes { get { if (_routes == null) { _routes = RouteTable.Routes; } return _routes; } set { _routes = value; } } 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.GenerateUrl(RouteName, null /* actionName */, null /* controllerName */, RouteValues, Routes, context.RequestContext, false /* includeImplicitMvcValues */); if (String.IsNullOrEmpty(destinationUrl)) { throw new InvalidOperationException(MvcResources.Common_NoRouteMatched); } context.Controller.TempData.Keep(); if (Permanent) { context.HttpContext.Response.RedirectPermanent(destinationUrl, endResponse: false); } else { context.HttpContext.Response.Redirect(destinationUrl, endResponse: false); } } }
RedirectToRouteResult和RedirectResult都是實現重定向,只不過RedirectToRouteResult的跳轉地址是經過路由信息中的Controller和Action的拼接來完成的,其餘均和RedirectResult相同!
ASP.NET MVC在Controller類中定義了幾個方法用於建立RedirectToRouteResult對象,固然也能夠直接在Action中建立RedirectToRouteResult對象並做爲方法的返回值。
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer { //省略其餘代碼 protected internal RedirectToRouteResult RedirectToAction(string actionName) { return RedirectToAction(actionName, (RouteValueDictionary)null); } protected internal RedirectToRouteResult RedirectToAction(string actionName, object routeValues) { return RedirectToAction(actionName, new RouteValueDictionary(routeValues)); } protected internal RedirectToRouteResult RedirectToAction(string actionName, RouteValueDictionary routeValues) { return RedirectToAction(actionName, null /* controllerName */, routeValues); } protected internal RedirectToRouteResult RedirectToAction(string actionName, string controllerName) { return RedirectToAction(actionName, controllerName, (RouteValueDictionary)null); } protected internal RedirectToRouteResult RedirectToAction(string actionName, string controllerName, object routeValues) { return RedirectToAction(actionName, controllerName, new RouteValueDictionary(routeValues)); } protected internal virtual RedirectToRouteResult RedirectToAction(string actionName, string controllerName, RouteValueDictionary routeValues) { RouteValueDictionary mergedRouteValues; if (RouteData == null) { mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, null, routeValues, includeImplicitMvcValues: true); } else { mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, RouteData.Values, routeValues, includeImplicitMvcValues: true); } return new RedirectToRouteResult(mergedRouteValues); } protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName) { return RedirectToActionPermanent(actionName, (RouteValueDictionary)null); } protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, object routeValues) { return RedirectToActionPermanent(actionName, new RouteValueDictionary(routeValues)); } protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, RouteValueDictionary routeValues) { return RedirectToActionPermanent(actionName, null /* controllerName */, routeValues); } protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, string controllerName) { return RedirectToActionPermanent(actionName, controllerName, (RouteValueDictionary)null); } protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, string controllerName, object routeValues) { return RedirectToActionPermanent(actionName, controllerName, new RouteValueDictionary(routeValues)); } protected internal virtual RedirectToRouteResult RedirectToActionPermanent(string actionName, string controllerName, RouteValueDictionary routeValues) { RouteValueDictionary implicitRouteValues = (RouteData != null) ? RouteData.Values : null; RouteValueDictionary mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, implicitRouteValues, routeValues, includeImplicitMvcValues: true); return new RedirectToRouteResult(null, mergedRouteValues, permanent: true); } protected internal RedirectToRouteResult RedirectToRoute(object routeValues) { return RedirectToRoute(new RouteValueDictionary(routeValues)); } protected internal RedirectToRouteResult RedirectToRoute(RouteValueDictionary routeValues) { return RedirectToRoute(null /* routeName */, routeValues); } protected internal RedirectToRouteResult RedirectToRoute(string routeName) { return RedirectToRoute(routeName, (RouteValueDictionary)null); } protected internal RedirectToRouteResult RedirectToRoute(string routeName, object routeValues) { return RedirectToRoute(routeName, new RouteValueDictionary(routeValues)); } protected internal virtual RedirectToRouteResult RedirectToRoute(string routeName, RouteValueDictionary routeValues) { return new RedirectToRouteResult(routeName, RouteValuesHelpers.GetRouteValues(routeValues)); } protected internal RedirectToRouteResult RedirectToRoutePermanent(object routeValues) { return RedirectToRoutePermanent(new RouteValueDictionary(routeValues)); } protected internal RedirectToRouteResult RedirectToRoutePermanent(RouteValueDictionary routeValues) { return RedirectToRoutePermanent(null /* routeName */, routeValues); } protected internal RedirectToRouteResult RedirectToRoutePermanent(string routeName) { return RedirectToRoutePermanent(routeName, (RouteValueDictionary)null); } protected internal RedirectToRouteResult RedirectToRoutePermanent(string routeName, object routeValues) { return RedirectToRoutePermanent(routeName, new RouteValueDictionary(routeValues)); } protected internal virtual RedirectToRouteResult RedirectToRoutePermanent(string routeName, RouteValueDictionary routeValues) { return new RedirectToRouteResult(routeName, RouteValuesHelpers.GetRouteValues(routeValues), permanent: true); } }
九、ViewResult
ViewResult內容包含了:PartialViewResult和ViewResult。ViewResult將視圖頁的內容響應給客戶端,而PartialViewResult稱分部視圖,其響應請求時不輸出那寫html、head、body等標籤,只是將分部視圖中內容返回!因爲ViewResult和PartialViewResult在進行【View呈現】的過程大體相同,因此此處就只針對ViewResult進行詳細解讀,而PartialViewRsult詳細過程將再也不敖述。(分部視圖的更多信息:關於如何PartialViewResult的使用)
public abstract class ViewResultBase : ActionResult { private DynamicViewDataDictionary _dynamicViewData; private TempDataDictionary _tempData; private ViewDataDictionary _viewData; private ViewEngineCollection _viewEngineCollection; private string _viewName; public object Model { get { return ViewData.Model; } } public TempDataDictionary TempData { get { if (_tempData == null) { _tempData = new TempDataDictionary(); } return _tempData; } set { _tempData = value; } } public IView View { get; set; } public dynamic ViewBag { get { if (_dynamicViewData == null) { _dynamicViewData = new DynamicViewDataDictionary(() => ViewData); } return _dynamicViewData; } } public ViewDataDictionary ViewData { get { if (_viewData == null) { _viewData = new ViewDataDictionary(); } return _viewData; } set { _viewData = value; } } //獲取或設置視圖引擎,ASP.NET有兩個視圖引擎,分別是:WebFormViewEngine、RazorViewEngine。 public ViewEngineCollection ViewEngineCollection { get { return _viewEngineCollection ?? ViewEngines.Engines; } set { _viewEngineCollection = value; } } public string ViewName { get { return _viewName ?? String.Empty; } set { _viewName = value; } } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } //若是沒有設置ViewName就將當前Action做爲ViewName if (String.IsNullOrEmpty(ViewName)) { ViewName = context.RouteData.GetRequiredString("action"); } ViewEngineResult result = null; if (View == null) { //經過視圖引擎去尋找視圖 result = FindView(context); View = result.View; } TextWriter writer = context.HttpContext.Response.Output; ViewContext viewContext = new ViewContext(context, View, ViewData, TempData, writer); //使用指定的編寫器對象來呈現指定的視圖上下文 View.Render(viewContext, writer); if (result != null) { result.ViewEngine.ReleaseView(context, View); } } protected abstract ViewEngineResult FindView(ControllerContext context); }
public class ViewResult : ViewResultBase { private string _masterName; public string MasterName { get { return _masterName ?? String.Empty; } set { _masterName = value; } } protected override ViewEngineResult FindView(ControllerContext context) { //根據View引擎去尋找View //此處ViewEngineCollection是ViewResultBase類中的一個屬性,表示視圖引擎集合。 ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName); //若是找到了指定的VIew,則返回。 if (result.View != null) { return result; } //沒有找到指定的View,那麼就將查找路徑給經過異常返回。 StringBuilder locationsText = new StringBuilder(); foreach (string location in result.SearchedLocations) { locationsText.AppendLine(); locationsText.Append(location); } throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, MvcResources.Common_ViewNotFound, ViewName, locationsText)); } }
public class PartialViewResult : ViewResultBase { /// <summary>Returns the <see cref="T:System.Web.Mvc.ViewEngineResult" /> object that is used to render the view.</summary> /// <returns>The view engine result.</returns> /// <param name="context">The controller context.</param> /// <exception cref="T:System.InvalidOperationException">An error occurred while the method was attempting to find the view.</exception> protected override ViewEngineResult FindView(ControllerContext context) { ViewEngineResult viewEngineResult = base.ViewEngineCollection.FindPartialView(context, base.ViewName); if (viewEngineResult.View != null) { return viewEngineResult; } StringBuilder stringBuilder = new StringBuilder(); foreach (string current in viewEngineResult.SearchedLocations) { stringBuilder.AppendLine(); stringBuilder.Append(current); } throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.Common_PartialViewNotFound, new object[] { base.ViewName, stringBuilder })); } }
Controller類中定義的建立ViewResult和PartialViewResult對象的方法:
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IController, IAsyncManagerContainer { //省略其餘代碼... //PartialViewResult protected internal PartialViewResult PartialView() { return this.PartialView(null, null); } protected internal PartialViewResult PartialView(object model) { return this.PartialView(null, model); } protected internal PartialViewResult PartialView(string viewName) { return this.PartialView(viewName, null); } protected internal virtual PartialViewResult PartialView(string viewName, object model) { if (model != null) { base.ViewData.Model = model; } return new PartialViewResult { ViewName = viewName, ViewData = base.ViewData, TempData = base.TempData, ViewEngineCollection = this.ViewEngineCollection }; } //ViewResult protected internal ViewResult View() { string viewName = null; string masterName = null; object model = null; return this.View(viewName, masterName, model); } protected internal ViewResult View(object model) { return this.View(null, null, model); } protected internal ViewResult View(string viewName) { string masterName = null; object model = null; return this.View(viewName, masterName, model); } protected internal ViewResult View(string viewName, string masterName) { return this.View(viewName, masterName, null); } protected internal ViewResult View(string viewName, object model) { return this.View(viewName, null, model); } protected internal virtual ViewResult View(string viewName, string masterName, object model) { if (model != null) { base.ViewData.Model = model; } return new ViewResult { ViewName = viewName, MasterName = masterName, ViewData = base.ViewData, TempData = base.TempData, ViewEngineCollection = this.ViewEngineCollection }; } protected internal ViewResult View(IView view) { return this.View(view, null); } protected internal virtual ViewResult View(IView view, object model) { if (model != null) { base.ViewData.Model = model; } return new ViewResult { View = view, ViewData = base.ViewData, TempData = base.TempData }; } }
ViewResult進行呈現的大體流程爲:
對於上述流程中的第三步中,建立視圖對象以後,經過它來對視圖頁進行處理。在對處理視圖頁時,首先要處理_ViewStart.cshtml文件(至關與asp.net中的Page_Load方法),以後再去處理請求的試圖頁。例如:若是在~/View/HomeController目錄下建立一個_ViewStart.cshtml文件,那麼以後當請求HomeController目錄下的任意視圖頁時,都會先執行_ViewStart.cshtml,若是再在~/View目錄下建立一個_ViewStart.cshtml的話,那麼在請求HomeController目錄下的任意視圖頁時,那麼兩個_ViewStart.cshtml都會先執行,且順序爲:先~/View目錄下後~/View/HomeController目錄下的_ViewStart.cshtml。
因爲ViewResult的詳細過程涉及內容較多,因此將另寫一篇博文來對其進行詳細分析:《白話學習MVC(十)View的呈現二》