概述
在ASP.NET MVC中,對於Action中得到的ActionResult如果是一個ViewResult對象,那么在進行View呈現時,則會先執行_ViewStart.cshtml,然后再去執行被請求的視圖頁,但是如果在控制器的Action中得到的ActionResult是一個PartialViewResult對象,那么在進行View呈現時,則不會執行_ViewStart.cshtml。
舉例驗證
例如:控制器代碼如下:
public class HomeController : Controller { public ActionResult Index() { return View("Index"); } public ActionResult PartView() { return PartialView("Index"); } }
⑴ 如果視圖中設置如下,即:將 Layout = "~/Views/Shared/_Layout.cshtml";定義在Index.cshtml中。
則ViewResult和PartialViewResult的輸出結果相同:
⑵ 如果視圖設置如下,即:將 Layout = "~/Views/Shared/_Layout.cshtml";定義在_ViewStart.cshtml中。
則ViewResult和PartialViewResult的輸出結果不同:
以上的實例,我們可見斷定,對於PartialViewResult對象進行View呈現時,不會執行 “_ViewStart.cshtml”(因為第二種情況下沒有執行母板頁中的代碼),為了更加具有說服力,我們再來看看ASP.NET MVC源代碼,並對比ViewResult和PartialViewResult來檢查我們的猜想是否正確!!
源碼驗證
由於對於ASP.NET MVC來說,進行View呈現的入口是執行ActionResult的ExecuteResult方法,而ViewResult和PartialViewResult都是繼承自ViewResultBase類,在ViewResultBase中定義了ExecuteResult 方法!
public abstract class ViewResultBase : ActionResult { //省略其他代碼... public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (string.IsNullOrEmpty(this.ViewName)) { this.ViewName = context.RouteData.GetRequiredString("action"); } ViewEngineResult viewEngineResult = null; if (this.View == null) { //執行FindView方法(在派生類中實現),通過視圖引擎來創建視圖對象! viewEngineResult = this.FindView(context); this.View = viewEngineResult.View; } TextWriter output = context.HttpContext.Response.Output; ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, output); this.View.Render(viewContext, output); if (viewEngineResult != null) { viewEngineResult.ViewEngine.ReleaseView(context, this.View); } } //該方法在派生類ViewResult和PartialViewResult中實現 protected abstract ViewEngineResult FindView(ControllerContext context); }
上圖可以看出,在ViewResult和PartialViewResult的FindView方法中,分別通過base.ViewEngineCollection的FindView和FindPartialView來創建ViewEngineResult對象(用於封裝當前請求的視圖對象和視圖引擎對象),我們知道base.ViewEngineCollection其實就是一個視圖引擎集合(默認情況下有:RazorViewEngine、WebFormViewEngine),而視圖引擎集合的FindView和FindPartialView方法,本質上就是遍歷執行每個視圖引擎的FindView和FindPartialView方法。
由於我們使用的是Razor引擎,所有就以RazorViewEngine為例來介紹:
this.CreatePartialView(...)和this.CreateView(...)方法都實現在派生類中!
上圖中,我們可以看出在創建RazorView對象時,ViewResult和PartialViewResult的區別在於參數:runViewStartPages,正式由於它,決定了在之后執行進行視圖頁處理時,也就是執行RazorView對象的Render(viewContext, output)方法時,是否執行“_ViewStar.cshtml”。
public abstract class BuildManagerCompiledView : IView { //省略其他代碼... public void Render(ViewContext viewContext, TextWriter writer) { if (viewContext == null) { throw new ArgumentNullException("viewContext"); } object obj = null; Type compiledType = this.BuildManager.GetCompiledType(this.ViewPath); if (compiledType != null) { obj = this._viewPageActivator.Create(this._controllerContext, compiledType); } if (obj == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.CshtmlView_ViewCouldNotBeCreated, new object[] { this.ViewPath })); } this.RenderView(viewContext, writer, obj); } //實現在派生類中 protected abstract void RenderView(ViewContext viewContext, TextWriter writer, object instance); } public class RazorView : BuildManagerCompiledView { //省略其他代碼... protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance) { if (writer == null) { throw new ArgumentNullException("writer"); } WebViewPage webViewPage = instance as WebViewPage; if (webViewPage == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.CshtmlView_WrongViewBase, new object[] { base.ViewPath })); } webViewPage.OverridenLayoutPath = this.LayoutPath; webViewPage.VirtualPath = base.ViewPath; webViewPage.ViewContext = viewContext; webViewPage.ViewData = viewContext.ViewData; webViewPage.InitHelpers(); if (this.VirtualPathFactory != null) { webViewPage.VirtualPathFactory = this.VirtualPathFactory; } if (this.DisplayModeProvider != null) { webViewPage.DisplayModeProvider = this.DisplayModeProvider; } WebPageRenderingBase startPage = null; //在這里這里這里這里.... if (this.RunViewStartPages) { //執行“_ViewStart.cshtml”中內容! startPage = this.StartPageLookup(webViewPage, RazorViewEngine.ViewStartFileName, this.ViewStartFileExtensions); } WebPageBase arg_D3_0 = webViewPage; HttpContextBase httpContext = viewContext.HttpContext; WebPageRenderingBase page = null; object model = null; arg_D3_0.ExecutePageHierarchy(new WebPageContext(httpContext, page, model), writer, startPage); } }