<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      ASP.NET MVC的View是如何被呈現出來的?[設計篇]

      在前面的四篇文章中,我們介紹了各種ActionResult以及相關的請求響應機制,但是與“View的呈現”相關的ActionResult是ViewResult。通過ViewResult的執行實現的對View的呈現比上面我們介紹的各種ActionResult要復雜得多,ASP.NET MVC內部設計了一個擴展的View引擎實現了最終的View呈現工作。[本文已經同步到《How ASP.NET MVC Works?》中]

      目錄
      一、View引擎中的View
      二、ViewEngine
      三、ViewResult的執行

      一、View引擎中的View

      ASP.NET MVC為我們提供了兩種View引擎,它們針對不同的動態View設計方式。一種是傳統的Web Form引擎,由于該引擎下View的設計與我們定義.aspx頁面一致,又稱為ASPX引擎。另外一種則是本書默認采用同時也是推薦使用的Razor引擎。在兩種View引擎的工作機制之前,有一個必須要知道的問題:View如何表示?提到View,很多ASP.NET MVC的開發人員可能首先想到的就是定義UI界面的.aspx文件(Web Form引擎)或者.cshtml/.vbhtml文件(Razor引擎)。其實對于View引擎來說,View是一個實現了IView接口類型的對象。如下面的代碼片斷所示,IView的定義非常簡單,僅僅具有唯一的Render方法根據指定的View上下文和TextWriter對象實現對View的呈現。

         1: public interface IView
         2: {    
         3:     void Render(ViewContext viewContext, TextWriter writer);
         4: }
         5:  
         6: public class ViewContext : ControllerContext
         7: {
         8:     //其他成員
         9:     public virtual bool ClientValidationEnabled { get; set; }
        10:     public virtual bool UnobtrusiveJavaScriptEnabled { get; set; }
        11:  
        12:     public virtual TempDataDictionary TempData { get; set; }    
        13:     [Dynamic]
        14:     public object                     ViewBag { [return: Dynamic] get; }
        15:     public virtual ViewDataDictionary ViewData { get; set; }
        16:     public virtual IView              View { get; set; }
        17:     public virtual TextWriter         Writer { get; set; }
        18: }
        19:  
        20: public abstract class HttpResponseBase
        21: {
        22:     //其他成員
        23:     public virtual TextWriter Output { get; set; }
        24: }

      IView用于呈現View的Render方法具有兩個參數,一個是表示View上下文的ViewContext對象。通過上面的代碼片斷可以看出ViewContext是ControllerContext的子類,用于表示狀態數據的ViewData、ViewBag和TempData對應著ControllerBase的同名屬性。也就是說當執行從Controller的某個Action方法返回的ViewResult的時候,通過創建的ViewContext保持的狀態數據直接來源于Controller對象。

      ViewContext具有兩個布爾類型屬性ClientValidationEnabled和UnobtrusiveJavaScriptEnabled表示是否支持客戶端驗證和Unobtrusive JavaScript。默認的情況下著兩個屬性通過同名的AppSettings配置項進行設置。如果應用不具有對應的配置,兩個屬性默認值為False。

         1: <configuration>
         2:   <appSettings>
         3:     <add key="ClientValidationEnabled" value="true"/>
         4:     <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
         5:   </appSettings>
         6: </configuration>

      配置的范圍是針對整個Web應用而言的,這個全局屬性還可以通過HtmlHelper的同名靜態屬性進行設置。值得一提的是,ASP.NET MVC 允許我們針對某個View開啟或者關閉對客戶端驗證和UnobtrusiveJavaScriptEnabled的支持,而這可以通過當前View的HtmlHelper的實例方法EnableClientValidation/EnableUnobtrusiveJavaScript來實現。

         1: public class HtmlHelper
         2: {
         3:     //其他成員    
         4:     public void EnableClientValidation();
         5:     public void EnableClientValidation(bool enabled);
         6:     public void EnableUnobtrusiveJavaScript();
         7:     public void EnableUnobtrusiveJavaScript(bool enabled);
         8:    
         9:     public static bool ClientValidationEnabled { get; set; }    
        10:     public static bool UnobtrusiveJavaScriptEnabled { get; set; }    
        11: }

      接口IView的Render方法的第二個參數是一個TextWriter對象。對于該方法來說,只要我們將內容寫入該TextWriter即完成了針對相關內容在View上的呈現,因為在調用Render方法的時候,作為該參數的是當前HttpResponse的Output屬性表示的TextWriter。

      二、ViewEngine

      View引擎的核心是一個ViewEngine對象,它實現了IViewEngine接口。如下面的代碼片斷所示,IViewEngine定義了兩個FindView和FindPartialView方法根據指定的Controller上下文、View名稱和布局文件名稱去獲取對應的View和Partial View,兩個方法中具有一個布爾類型的參數useCache表示是否啟用緩存。另一個方法ReleaseView用于釋放View對象。

         1: public interface IViewEngine
         2: {    
         3:     ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache);
         4:     ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache);
         5:     void ReleaseView(ControllerContext controllerContext, IView view);
         6: }

      FindView和FindPartialView方法返回的并不是實現了IView接口的類型的對象,而是一個類型為System.Web.Mvc.ViewEngineResult對象。如下面的代碼片斷所示,ViewEngineResult的只讀屬性View和ViewEngine屬性表示找到的View對象和表示自身的ViewEngine對象。在成功獲取到對應View的情況下這兩個屬性會通過構造函數進行初始化。如果沒有找到相應的View,則將一個搜尋位置列表傳入另一個構造函數創建一個ViewEngineResult,而只讀屬性SearchedLocations表示的就是這么一個搜尋位置列表。

         1: public class ViewEngineResult
         2: {    
         3:     public ViewEngineResult(IEnumerable<string> searchedLocations);
         4:     public ViewEngineResult(IView view, IViewEngine viewEngine);
         5:    
         6:     public IEnumerable<string> SearchedLocations { get; }
         7:     public IView               View { get; }
         8:     public IViewEngine         ViewEngine { get; }
         9: }

      如果返回的ViewEngineResult包含一個具體的View,那么這個View將會最終被呈現出來。反之,如果ViewEngineResult僅僅包含一個通過SearchedLocations屬性表示的在獲取目標View過程中使用的搜索位置列表,那么最終呈現出來的就是如下圖所示的包含該列表的錯誤頁面。

      image

      我們可以通過一個簡單的實例來驗證這一點。在通過Viual Studio的ASP.NET MVC項目模板創建的空Web應用中,我們定義了如下一個HomeController。在默認的Action方法Index中,我們通過ViewEngines的靜態只讀屬性Engines得到一個全局ViewEngine列表,并調用其FindView方法試圖去尋找一個根本不存在View(“NonExistentView”)。最后我們將得到的ViewEngineResult對象的SearchedLocations屬性表示的搜尋位置列表呈現出來。

         1: public class HomeController : Controller
         2: {
         3:     public void Index()
         4:     {
         5:         ViewEngineResult result = ViewEngines.Engines.FindView(ControllerContext, "NonExistentView", null);
         6:         foreach (string location in result.SearchedLocations)
         7:         {
         8:             Response.Write(location + "<br/>");
         9:         }
        10:     }
        11: }

      運行我們的程序后表示在獲取目標View中采用的搜尋位置列表會如下圖所示的方式呈現出來,而這個列表與上圖是完全一致的。

      image

      在上面實例演示中涉及到了一個重要的靜態類型ViewEngines,它通過如下定義的只讀屬性Engines維護一個全局ViewEngine列表。從給出的定義可以看出,兩個原生的ViewEngine在初始化的時候就被添加到了該列表中,它們的類型就是分別代表Web Form和Razor引擎的WebFormViewEngineRazorViewEngine如果我們創建了一個自定義View引擎,相應的ViewEngine也可以通過ViewEngines進行注冊。

         1: public static class ViewEngines
         2: {
         3:     private static readonly ViewEngineCollection _engines = new ViewEngineCollection { new WebFormViewEngine(), new RazorViewEngine() };
         4:    
         5:     public static ViewEngineCollection Engines
         6:     {
         7:         get { return _engines;}
         8:     }
         9: }
        10:  
        11: public class ViewEngineCollection : Collection<IViewEngine>
        12: {
        13:     //其他成員
        14:     public virtual ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName);
        15:     public virtual ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName);
        16: }

      ViewEngines的靜態只讀屬性Engines的類型是ViewEngineCollection,它是一個元素類型為IViewEngine的集合。ViewEngineCollection同樣定義了FindView/FindPartialView這兩個方法用于獲取指定名稱的View和分部View,在方法內部它會遍歷集合中 的ViewEngine對象并調用它們的同名方法直到找的一個具體的View或者Partial View。由于WebFormViewEngine排在RazorViewEngine之前,所以前者會被優先使用,這可以從上面兩張截圖所示的搜尋位置列表看出來(先搜索.aspx和.ascx,再搜索.cshtml和.vbhtml)。

      對于ViewEngineCollection的FindView/FindPartialView方法來說,不知道讀者是否注意到了它們沒有一個表示是否采用緩存的useCache參數。實際上當這兩個方法被調用的時候,會先采用緩存的方式調用相應的ViewEngine,如果返回為Null,則以不采用緩存的方式再次調用它們。

      三、ViewResult的執行

      View引擎對View的獲取以及對View的呈現最初是通過ViewResult觸發的,那么兩者是如何銜接的呢?這是本小節著重討論的問題,在這之前我們不妨先來看看ViewResult的定義。如下面的代碼片斷所示,表示ViewResult的類型ViewResult是抽象類ViewResultBase的子類。

         1: public class ViewResult : ViewResultBase
         2: {    
         3:     protected override ViewEngineResult FindView(ControllerContext context);
         4:     public string MasterName { get; set; }
         5: }
         6:  
         7: public abstract class ViewResultBase : ActionResult
         8: {   
         9:     public override void ExecuteResult(ControllerContext context);
        10:     protected abstract ViewEngineResult FindView(ControllerContext context);
        11:   
        12:     public object                     Model { get; }
        13:     public TempDataDictionary         TempData { get; set; }    
        14:     [Dynamic]
        15:     public object                     ViewBag { [return: Dynamic] get; }
        16:     public ViewDataDictionary         ViewData { get; set; }   
        17:     public string                     ViewName { get; set; }
        18:     public ViewEngineCollection       ViewEngineCollection { get; set; }
        19:     public IView                      View { get; set; }
        20: }

      ViewResultBase的只讀屬性Model表示作為View的Model對象,三個表示數據狀態的屬性(ViewData、ViewBag和TempData)來源于Controller的同名屬性。View和ViewName屬性則是代表具體的View對象和View的名稱。ViewEngineCollection屬性值默認來源于ViewEngines的靜態屬性Engines代表的全局ViewEngine列表。

      ViewResultBase用于獲取具體View的FindView方法在ViewResult類中被實現,后者提供了額外的屬性MasterName表示布局文件名稱。在FindView方法的內部會直接調用ViewEngineCollection屬性的FindView方法,如果返回的ViewEngineResult包含一個具體的View(View屬性不為空),則直接返回該ViewEngineResult,否則拋出一個InvalidOperation異常,并將通過ViewEngineResult的SearchedLocations屬性表示的搜尋位置列表格式化成一個字符串作為該異常的消息,所以圖8-5所示的搜尋位置列表實際上是拋出的InvalidOperation異常的消息。

      ASP.NET MVC的View引擎涉及到的相關的類型/接口以及它們之間的關系可以通過如圖下所示的UML來表示。ViewResult通過靜態類型ViewEngines利用View引擎激活對應的View對象并最終將View的內容呈現出來。

      image

      與除EmptyResult以外的所有ActionResult類型一樣,抽象類Conrtoller中提供了相應的方法輔助創建ViewResult。如下面的代碼片斷所示,Controller具有如下一系列View方法幫助我們根據指定的View名稱、View對象、布局文件名稱和Model對象創建相應的ViewResult。

         1: public abstract class Controller : ControllerBase, ...
         2: {
         3:     //其他成員   
         4:     protected ViewResult View();
         5:     protected ViewResult View(object model);
         6:     protected ViewResult View(string viewName);
         7:     protected ViewResult View(IView view);
         8:     protected ViewResult View(string viewName, object model);
         9:     protected ViewResult View(string viewName, string masterName);
        10:     protected virtual ViewResult View(IView view, object model);
        11:     protected virtual ViewResult View(string viewName, string masterName, object model);
        12: }

      ViewResult與View引擎的交互體現在用于執行執行ActionView的ExecuteResult上。如下面的代碼片斷所示,如果View屬性為Null,會調用FindView方法得到一個用于封裝指定名稱(如果沒有執行則采用當前的Action名稱作為View名稱)的View的ViewEngineResult對象,并將其View屬性作為自身的View。然后創建View上下文,并將該上下文和當前HttpResponse的Output屬性代表的TextWriter對象作為參數調用View對象的Render方法實現對View的最終呈現。View呈現完成之后,通過ViewEngineResult得到對應的ViewEngine,并調用其Release對象對View進行回收操作。

         1: public abstract class ViewResultBase : ActionResult
         2: {
         3:     //其他成員
         4:     public override void ExecuteResult(ControllerContext context)
         5:     {   
         6:         //其他操作     
         7:         if (string.IsNullOrEmpty(this.ViewName))
         8:         {
         9:             this.ViewName = context.RouteData.GetRequiredString("action");
        10:         }
        11:         ViewEngineResult result = null;
        12:         if (this.View == null)
        13:         {
        14:             result = this.FindView(context);
        15:             this.View = result.View;
        16:         }
        17:         TextWriter output = context.HttpContext.Response.Output;
        18:         ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, output);
        19:         this.View.Render(viewContext, output);
        20:         if (result != null)
        21:         {
        22:             result.ViewEngine.ReleaseView(context, this.View);
        23:         }
        24:     }
        25: }

      ViewResult為們提供了一種與View引擎交互的手段,其實在進行View的獲取和呈現的時候完全可以拋開ViewResult,直接利用View引擎來完成,如下兩種Action方法的定義是完全等效的。

         1: //Action方法直接返回ViewResult
         2: public class HomeController : Controller
         3: {
         4:     public ActionResult Index()
         5:     {
         6:         return View();
         7:     }
         8: }
         9:  
        10: //Action方法直接調用View引擎
        11: public class HomeController : Controller
        12: {
        13:     public void Index()
        14:     {
        15:         string viewName = ControllerContext.RouteData.GetRequiredString("action");
        16:         ViewEngineResult result = ViewEngines.Engines.FindView(ControllerContext, viewName, null);
        17:         if (null == result.View)
        18:         { 
        19:             throw new InvalidOperationException(FormatErrorMessage(viewName,result.SearchedLocations));
        20:         }
        21:         try
        22:         {
        23:             ViewContext viewContext = new ViewContext(ControllerContext, result.View, this.ViewData, this.TempData, Response.Output);
        24:             result.View.Render(viewContext, viewContext.Writer);
        25:         }
        26:         finally
        27:         {
        28:             result.ViewEngine.ReleaseView(ControllerContext, result.View);
        29:         }
        30:     }
        31:  
        32:     private string FormatErrorMessage(string viewName, IEnumerable<string> searchedLocations)
        33:     {
        34:         string format = "The view '{0}' or its master was not found or no view engine supports the searched locations. The following locations were searched:{1}";
        35:         StringBuilder builder = new StringBuilder();
        36:         foreach (string str in searchedLocations)
        37:         {
        38:             builder.AppendLine();
        39:             builder.Append(str);
        40:         }
        41:         return string.Format(CultureInfo.CurrentCulture, format, viewName, builder);
        42:     }
        43: }

      上面我們僅僅介紹了ViewResult利用View引擎進行View的獲取和呈現,其實當我們調用HtmlHelper的擴展方法Partial將指定的Partial View的HTML呈現出來時,內部調用View引擎的方式與之類

      ASP.NET MVC的View是如何被呈現出來的?[設計篇]
      ASP.NET MVC的View是如何被呈現出來的?[實例篇]

      posted @ 2012-08-22 09:09  Artech  閱讀(18568)  評論(36)    收藏  舉報
      主站蜘蛛池模板: 国产亚洲无线码一区二区| 2020国产欧洲精品网站| 亚洲国产精久久久久久久春色| 噜噜噜噜私人影院| 亚洲精品欧美综合二区| 国产美女被遭强高潮免费一视频| 无码日韩精品一区二区人妻| 亚洲第四色在线中文字幕| 国产精品日日摸夜夜添夜夜添无码| 国产97人人超碰caoprom| av在线播放无码线| 18禁精品一区二区三区| 国产午夜福利精品视频 | 国产一区二区在线影院| 人妻av中文字幕无码专区| 久久精品国产亚洲av熟女| 国产在线精品福利91香蕉| 嫩草欧美曰韩国产大片| 人人妻人人狠人人爽天天综合网| 国产成人一区二区三区影院动漫| 国产蜜臀av在线一区二区| 99久久国产成人免费网站| 日韩毛片在线视频x| 国偷自产一区二区三区在线视频| 日韩精品一区二区亚洲专区 | 国产麻豆91网在线看| 日韩东京热一区二区三区| 平遥县| 国产在线观看免费人成视频| 国产毛片子一区二区三区| 91香蕉国产亚洲一二三区| 北京市| 欧美熟妇乱子伦XX视频| 看黄a大片日本真人视频直播| 亚洲精品久久久久国色天香| 亚洲视频免费一区二区三区| AV人摸人人人澡人人超碰| 国产精品福利自产拍久久| 西西人体44WWW高清大胆| 娇妻玩4p被三个男人伺候| 国产亚洲人成网站在线观看|