Agenda
前言
上一篇說到最終會透過一個實現IView
物件(Razor是透過RazorView
)來完成,RenderView
方法將BuildManagerCompiledView
方法取得物件轉換型別成WebViewPage
.
.cshtml
最終會編譯成一個繼承WebViewPage
檔案.
本篇會來解析View
編譯原理
我有做一個可以針對於Asp.net MVC Debugger的專案,只要下中斷點就可輕易進入Asp.net MVC原始碼.
WebViewPage
WebViewPage
繼承樹最頂層有個WebPageExecutingBase
抽象類別,他擁有一個抽象方法Execute
,View
轉成c#
程式會建立一個類別就會繼承於WebViewPage
並把使用者頁面程式碼實現在Execute
方法.
1 | public abstract void Execute(); |
先來看一下View
產生的DLL檔案會放在哪裡
透過在View
檔案上寫@GetType().Assembly.Location
.
在頁面上顯示DLL
存放位置,一般會放在Temp
資料夾區中
可以根據顯示路徑找到View
編譯成DLL
1 | public class _Page_Views_Shared__Layout_cshtml : WebViewPage<object> |
我使用JustDecomplie
反編譯工具,查看原始碼.
下圖對於View
檔案產生DLL
反編譯
透過反編譯工具可以看到原始碼,每個頁面都會產生相對應的類別並繼承於WebViewPage<object>
類別(會因為使用泛型,因為有一個@Model
)
Page_Views_Home_About_cshtml
類別命名有個規則.Page_Views_{ViewfolderName}_{ViewFileName}_{ExtensionFileName}
我目前看到的是一個About
的cshtml
檔案(About.cshtml
).
看到override void Execute()
將我們頁面上的邏輯透過WriteLiteral
將資料寫到Output
上,在ApplicationStartPage
有WriteLiteral
實作方式.
1 | public override void WriteLiteral(object value) |
呼叫WebViewPage.ExecutePageHierarchy方法時機
在RazorView
類別中的RenderView
方法最下面有一段程式碼.
先判斷是否取得StartPage
在呼叫ExecutePageHierarchy
方法進行頁面的渲染.
1 | WebPageRenderingBase startPage = null; |
ApplicationStartPage and WebPageRenderingBase
WebViewPage
類別關係圖如下,WebViewPage
擁有個複雜繼承樹.
主要分為兩派,在微軟官網有張圖來表示上面兩個比較
ApplicationStartPage
:當站台被啟動時會使用WebPageHttpModule
(IHttpModule
)初始化並呼叫ApplicationStartPage
的ExecuteStartPageInternal
找尋_appstart.cshtml
檔案來執行.ASP.NET Web Pages (Razor) 網站的自訂全網站行為
_AppStart.cshtml
頁面上運作。 當要求傳入頁面中,和如果這是第一個要求任何頁面在網站中,ASP.NET
會先檢查是否_AppStart.cshtml
頁面存在。 如果是的話,任何程式碼中_AppStart.cshtml
頁面上執行,並執行要求的頁面。
WebPageRenderingBase
:透過ExecutePageHierarchy
呼叫BaseLayout
頁面或執行請求Execute
方法
WebPageBase
類別中ExecutePageHierarchy
重載實作,透過ExecutePageHierarchy
呼叫開發者實現Execute
方法(Page_Views_Home_About_cshtml.Execute
方法).
1 | public override void ExecutePageHierarchy() |
WebViewPage vs WebViewPage
c#
有一個關鍵字new
對於類別成員修飾詞
new
關鍵字做為宣告修飾詞使用時,會明確隱藏繼承自基底類別的成員。當您隱藏繼承的成員時,該成員的衍生版本就會取代基底類別版本
new 修飾詞 (C# 參考)
我覺得這個關鍵字有點打壞物件導向的概念,因為他會把父類別原本的成員隱藏起來.強制替換成子類.
但我看到WebViewPage<TModel>
實作時覺得new
原來可以這麼好用
WebViewPage<TModel>
很巧妙使用new
把View
重點成員物件轉成泛型.可以讓我們在Razor
或aspx
可以更方便使用.
1 | public abstract class WebViewPage<TModel> : WebViewPage |
所以之後如果有遇到類似情況(需要使用泛型替代父類別object
類型成員可以考慮使用new
)
小結:
View
頁面程式會轉成一個類別繼承於WebViewPage
抽象類別,並把我們撰寫邏輯填充在Execute
方法中.讓Asp.net MVC來呼叫.
這裡設計非常巧妙透過一個抽象類別和一個動態編譯程式,讓View
更有彈性可以透過Razor
語法實現View
邏輯(更人性化).
WebViewPage<TModel>
很巧妙使用new
把View
重點成員物件轉成泛型.可以讓我們在Razor
或aspx
可以更方便使用.
最後透過呼叫ActionResult.ExecuteResult
方法將資料塞到Response
物件中,提供回傳給Client
端,最後執行資源Release
動作.
後面幾篇會利用前面所學來改寫MVC框架.
此文作者:Daniel Shih(石頭)
此文地址: https://isdaniel.github.io/ithelp-day25/
版權聲明:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!