Asp.Net MVC5 檢視頁面編譯呼叫流轉過程,以及頁面Web展示
例如:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
以上是一個最簡單的View檢視返回撥用
這個return View()執行的結果是直接返回HTML到Web頁面。這個View()是個ViewResult類,如何會返回HTML呢?在CSHTML裡面的@符號後面的C#類,變數或者是強型別Model是如何解析的?下面簡單的分析下。
View()返回的是ViewResult類的例項,繼承自abstract ViewResultBase, ViewResultBasey又繼承自抽象類ActionResult,在ActionResult裡面有一個 ExecuteResult抽象方法,引數為控制器上下文.
ExecuteResult方法會呼叫型別為ViewEngineResult的FindView方法,傳遞ControllerContext引數。獲取到當前頁面IView,IView則呼叫IView類的抽象Render方法。展開對整個CSHMTL頁面的引擎。噹噹前檢視呼叫Render方法,會導致BuildManagerCompiledView和RazorView兩個類的Render方法被呼叫。最後在RazorView的RenderView方法裡面呼叫 :webViewPage.ExecutePageHierarchy(new WebPageContext(context: viewContext.HttpContext, page: null, model: null), writer, startPage);會呼叫WebViewPage裡面的ExectuePageHierarchy方法,因為webViewPage裡面沒有三個過載的ExectuePageHierarchy方法,會轉到WebViewPage的基類WebPageBase執行它的ExectuePageHierarchy方法。此方法裡面有三個動作,入棧(push),執行頁面(startpage.Execute),出站(pop).
入棧會把當前httpResonse.Response.Output放在當前Current屬性裡,把當前環境下的textwriter入棧,作為臨時變數。頁面執行會跳轉到類StartPage裡面,StartPage.Execute會呼叫Execute執行當前的首頁或者是母版頁或者是佈局頁面。比如ViewStart.CSHTML.則會被編譯成_Page_View_ViewStart.CSHTML.繼承自ViewStartPage,當Execute被呼叫的時候,實際上是呼叫的_Page_View_ViewStart.CSHTML裡面的Execute方法。這個方法是事先被編譯好的。在Asp.Net MVC執行期間。可以通過修改MVC根目錄下webconfig配置檔案的Compilation欄位設定執行期間被編譯的CSHMTL檔案的路徑。在Compilation位元組新增tempDirectory欄位,Value為路徑名即可。在Visual Studio2015下面可以通過Reflector 9.0反編譯上面路徑下被編譯程式集。Execute被呼叫之後,會呼叫一個RunPage方法。RunPage會獲取當前頁面然後呼叫ExectuePageHierarchy方法。ExectuePageHierarchy會Base.ExectuePageHierarchy.當前頁面一般會被編譯成WebViewPage的派生類。WebViewPage又派生自WebPageBase。所以Base.ExectuePageHierarchy.會呼叫webPageBase裡面的ExectuePageHierarchy.。
Execute呼叫的是已經編譯好的CSHTML頁面。例如控制器為Account,檢視Login,那麼MVC會把它編譯成:名稱為_Page_Views_Account_Login_Cshtml的類,這個類繼承自WebViewPage<TModel>。WebViewPage<TModel>又繼承自WebViewPage,WebViewPage則繼承自WebPageBase。
WebPageBase.ExectuePageHierarchy兩個引數方法呼叫了過載的三個引數方法,新增了一個StartPage:null.重複上面的動作,入棧,因為StartPage==null,所以會呼叫WebViewPage.ExectuePageHierarchy. WebViewPage.ExectuePageHierarchy.同樣的呼叫Base.ExectuePageHierarchy.然後再呼叫Execute把當前頁面例如:_Page_Account_Login_Cshtml這種頁面的HTML以及指令碼,以及C#類語言Model等寫入當前流。至此,整個過程完成。Render呼叫結束。
_Page_Account_Login_Cshtml類的程式碼如下:
public class _Page_Views_Account_Login_cshtml : WebViewPage<LoginViewModel>
{
// Methods
public _Page_Views_Account_Login_cshtml();
public override void Execute();
// Properties
protected global_asax ApplicationInstance { get; }
// Nested Types
[CompilerGenerated]
private static class <>o__3
{
// Fields
public static CallSite<Func<CallSite, object, string, object>> <>p__0;
public static CallSite<Func<CallSite, object, object>> <>p__1;
public static CallSite<Action<CallSite, _Page_Views_Account_Login_cshtml, object>> <>p__2;
public static CallSite<Func<CallSite, object, object>> <>p__3;
public static CallSite<Func<CallSite, object, object>> <>p__4;
public static CallSite<Func<CallSite, object, string>> <>p__5;
}
}
Expand Methods
在繼承自WebStartPage和WebViewPage的編譯類中,Execute方法部分程式碼如下:
public override void Execute()
{
if (<>o__3.<>p__0 == null)
{
CSharpArgumentInfo[] argumentInfo = new CSharpArgumentInfo[] { CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) };
<>o__3.<>p__0 = CallSite<Func<CallSite, object, string, object>>.Create(Binder.SetMember (CSharpBinderFlags.None, "Title", typeof(_Page_Views_Account_Login_cshtml), argumentInfo));
}
<>o__3.<>p__0.Target(<>o__3.<>p__0, base.get_ViewBag(), "登入");
base.BeginContext("~/Views/Account/Login.cshtml", 0x56, 8, true);
this.WriteLiteral("\r\n\r\n<h2>");
base.EndContext("~/Views/Account/Login.cshtml", 0x56, 8, true);
base.BeginContext("~/Views/Account/Login.cshtml", 0x5f, 13, false);
if (<>o__3.<>p__2 == null)
{
CSharpArgumentInfo[] infoArray2 = new CSharpArgumentInfo[] { CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null) };
<>o__3.<>p__2 = CallSite<Action<CallSite, _Page_Views_Account_Login_cshtml, object>>.Create (Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded | CSharpBinderFlags.InvokeSimpleName, "Write", null, typeof(_Page_Views_Account_Login_cshtml), infoArray2));
}
if (<>o__3.<>p__1 == null)
{
CSharpArgumentInfo[] infoArray3 = new CSharpArgumentInfo[] { CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null) };
<>o__3.<>p__1 = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember (CSharpBinderFlags.None, "Title", typeof(_Page_Views_Account_Login_cshtml), infoArray3));
}
<>o__3.<>p__2.Target(<>o__3.<>p__2, this, <>o__3.<>p__1.Target(<>o__3.<>p__1, base.get_ViewBag()));
base.EndContext("~/Views/Account/Login.cshtml", 0x5f, 13, false);
base.BeginContext("~/Views/Account/Login.cshtml", 0x6c, 12, true);
this.WriteLiteral("。</h2>\r\n<div");
}
類繼承結構:
WebViewPage-》WebPageBase-》WebPageRenderingBase-》WebPageExecutingBase
WebStartPage->StartPage->WebPageRenderingBase->WebPageExecutingBase
檢視類繼承方法IView-》BuildManagerCompiledView -》RazorView.
相關文章
- Asp.Net中動態頁面轉靜態頁面ASP.NET
- 頁面渲染:過程分析
- web頁面Web
- 頁面載入全過程
- 【面試】Web 頁面請求歷程面試Web
- ASP.NET 頁面物件模型 (轉)ASP.NET物件模型
- router-view子頁面呼叫父頁面方法更新父頁面引數View
- 【轉】改變檢視頁面原始碼的程式原始碼
- ASP.NET Web Forms – HTML 頁面簡介ASP.NETWebORMHTML
- js頁面跳轉的問題(跳轉到父頁面、最外層頁面、本頁面)JS
- [譯]ASP.NET Core 2.0 佈局頁面ASP.NET
- 玩轉php環境日常更新---頁面展示PHP
- 【問題記錄】— web頁面呼叫本地程式Web
- “asp.net頁面跳轉”補遺ASP.NET
- js頁面展示省市聯動JS
- 頁面展示多表join的sqlSQL
- web頁面測試Web
- ASP.NET Web Pages – 頁面佈局簡介ASP.NETWeb
- 瀏覽器頁面載入過程瀏覽器
- JS 頁面載入過程問題JS
- asp.net中一個頁面跳轉,後一個頁面操作內容後返回先前頁面,並使得先前頁面資料重新整理ASP.NET
- 5.7(頁面展示紅星照耀中國)
- asp.net 頁面載入ASP.NET
- ASP.NET頁面Trace技巧ASP.NET
- 在VC6.0中呼叫瀏覽器訪問WEB頁面 (轉)瀏覽器Web
- 從輸入頁面地址到展示頁面資訊都發生了些什麼?
- 執行時的頁面構建過程
- [轉]如何使jsp頁面在EBS中自動編譯JS編譯
- web頁面效能測試Web
- vue跨頁面呼叫函式Vue函式
- Flutter頁面保活及保持頁面跳轉位置Flutter
- web頁面引用相關檔案或者頁面方式彙總Web
- ASP.NET頁面跳轉的三種方法ASP.NET
- 編寫web2.0爬蟲——頁面抓取部分Web爬蟲
- 前端學習筆記:通過H5頁面呼叫不同客戶端的原生頁面前端筆記H5客戶端
- 北大青鳥網站資訊展示頁面網站
- vue頁面跳轉Vue
- Flutter頁面跳轉Flutter