WebForm頁面內(nèi)容輸出的細節(jié)分析
老趙前日的這篇博文講的是有關ASP.NET WebForm頁面內(nèi)容輸出方式的內(nèi)容。盡管這個話題很老,不過在ASP.NET MVC中同樣適用,而且適用的情況有增無減,因此十分重要。希望這篇文章能夠幫助你更好的理解ASP.NET WebForm頁面內(nèi)容輸出的細節(jié)。
這次我們談的話題是“WebForm頁面上輸出內(nèi)容的方式”。這其實是一個非常舊的話題了,因為本文的內(nèi)容甚至可以運用于ASP.NET 1.1之上。不過這個話題的適用范圍很廣,因為即使是目前***的ASP.NET MVC框架,它的默認視圖引擎依舊是基于ASP.NET WebForm的(如Page,Control,MasterPage)。甚至說,由于ASP.NET MVC框架的特性,我們會遇到更多在頁面上“直接輸出”內(nèi)容的情況。因此,這個話題在ASP.NET MVC應用中可能由為重要。
那么就拿ASP.NET MVC舉例吧。假如,我們在頁面上生成一個Partial View,我們可以這么做:
- < % Html.RenderPartial("MyPartialView"); %>
然而,在前一篇文章中我們提出了一個新的方法Partial,它返回一個字符串,它可以在頁面上這樣使用:
- < %= Html.Partial("MyPartialView") %>
一個aspx頁面會被編譯成Page類的一個子類,這個子類的主要“功能”是覆蓋了基類的Render方法:
- public class MyPage : Page
- {
- protected override void Render(HtmlTextWriter writer)
- {
- ...
- }
- }
我們平時在aspx頁面中編寫的大量內(nèi)容,其實都會變成操作writer的代碼。例如使用writer.Write方法輸出內(nèi)容,或者把writer交給子控件的Render方法用于生成內(nèi)容。那么,以上兩種頁面上的標記分別又是如何操作writer的呢?
- < %= expression %>
首先是< %= %>標記。< %= %>標記內(nèi)包含的是一個“表達式”,因此它不能以分號結尾。表達式內(nèi)部的數(shù)據(jù)就會直接寫入writer。例如這樣的標記:
- < %= DateTime.Now %>
在編譯過后就成為:
- writer.Write(DateTime.Now)
與< %= %>標記不同,< % %>標記中間其實包含的是“語句”。語句自然可以有多行,自然每行***需要有分號,這就像我們平時寫C#代碼那樣。不過實際上,語句的功能其實并不是為了“輸出內(nèi)容”,而是用來“控制邏輯”。例如,您在頁面上寫了這樣的代碼:
- < % Func< int, bool> odd = i => i % 2 != 0; %>
這樣就相當于您在Render方法內(nèi)部聲明了一個局部變量odd,它的類型是一個Func< int, bool>委托。而如果您編寫這樣的代碼:
- < % for (int i = 0; i < 10; i++) { %>
- < span>
- < %= i + 1 %>
- < /span>
- < % } %>
則生成的Render方法中就會包含:
- for (int i = 0; i < 10; i++)
- {
- writer.Write("< span>");
- writer.Write(i + 1);
- writer.Write("< /span>");
- }
如果是寫在頁面上的普通HTML標記,編譯后就被當作普通字符串來處理了。有些朋友一直談“客戶端控件”等等,其實如果一個元素上沒有runat="server"標記,ASP.NET只是把它們當作普通字符串處理,并不會有任何“HTML元素”的概念。當然,上面的代碼表現(xiàn)的是“意圖”,事實上在編譯過后aspx頁面中的空格和換行等字符也會包含在輸出的內(nèi)容中1。
那么,既然< % %>中包含的是用來控制邏輯的語句,本身不是用來表示輸出的,那么為什么剛才代碼中的Html.RenderPartial方法也會生成頁面內(nèi)容呢?那是因為RenderPartial方法直接向當前HttpContext.Response.Output里寫入字符了。很多朋友經(jīng)常使用Response.Write來輸出內(nèi)容,其實在Write方法內(nèi)部就是輸出到Output中。
事實上,即使我們的頁面中使用了HtmlTextWriter來輸出內(nèi)容,但它內(nèi)部也是封裝了Output所暴露出的TextWriter中。為了驗證,您可以在代碼中設置斷點并觀察Render方法的writer參數(shù),在“正常情況下”可以發(fā)現(xiàn)writer.InnerWriter屬性是一個HttpWriter對象,這是個TextWriter的子類,也是ASP.NET中定義的內(nèi)部類型。
這便是ASP.NET WebForm頁面內(nèi)容輸出的細節(jié)。那么請問,以下兩種輸出方式的區(qū)別是什么呢?
- < %= "Hello World" %>
- < % Response.Write("Hello World"); %>
從效果上看,兩者沒有任何區(qū)別。但是實際上前者是使用頁面的HtmlTextWriter對象輸出的,而后者則直接向Response.Output里輸出內(nèi)容。這個區(qū)別看似不重要,但其實它會涉及到我們很多開發(fā)過程中可用的實踐方式。在今后的文章中,我會提出生成頁面內(nèi)容的一些準則,解釋這些準則的原因,并指出ASP.NET MVC本身是如何破壞這些設計準則的。
自然,修改版本的ASP.NET MVC會發(fā)布在MvcPatch項目中。
【編輯推薦】