在 ASP.NET WebForm(含 MVC 預設視圖引擎)中,頁面輸出內容的方式不只一種:`<%= %>`、`<% %>`、`<%: %>`(Razor)、`Response.Write()`、`HtmlTextWriter` 等。它們最終都會寫入同一個 `HttpResponse.Output` 流,但執行時機、編碼處理、可測試性、架構合規性卻大相徑庭。本文深入剖析編譯後的 `Render` 方法,揭示輸出機制的本質差異。
.aspx 頁面編譯後成為 `Page` 子類,核心是覆寫 `Render(HtmlTextWriter writer)`:
public class MyPage : Page
{
protected override void Render(HtmlTextWriter writer)
{
// 靜態 HTML 字串 → writer.Write("...")
// <%= 運算式 %> → writer.Write(運算式)
// <% 陳述式 %> → 直接成為 C# 陳述式,可控制流程
// 控制項.Render() → 控制項遞迴呼叫 writer
}
}
`HtmlTextWriter` 內部封裝 `TextWriter`(實際為內部型別 `HttpWriter`),統一輸出至 `Response.Output`。
| 標記 | 內容類型 | 編譯結果 | 典型用途 |
|---|---|---|---|
<%= expr %> | 運算式 (無分號) | writer.Write(expr); | 輸出變數、屬性、方法回傳值 |
<% stmt %> | 陳述式 (可多行、有分號) | 直接內嵌 C# 程式碼 | 迴圈、判斷、變數宣告、邏輯控制 |
<%: expr %> | 運算式 (Razor/ASP.NET 4+) | writer.Write(HttpUtility.HtmlEncode(expr)); | **預設 HTML 編碼**,防 XSS |
<% for (int i = 0; i < 10; i++) { %>
<span><%= i + 1 %></span>
<% } %>
編譯後等同:
for (int i = 0; i < 10; i++) {
writer.Write("");
writer.Write(i + 1);
writer.Write("");
}
<%= "Hello World" %> // → writer.Write("Hello World")
<% Response.Write("Hello World"); %> // → Response.Output.Write("Hello World")
**關鍵差異**:
ASP.NET WebForm 將「輸出」集中於 `HtmlTextWriter`,這是**管道模式**的體現:
`Response.Write()` 打破了這個管道,屬於**反模式**。
理解頁面輸出機制,不只是為了面試題,更是為了寫出**可維護、可測試、安全、架構合規**的視圖層代碼。下次在 `.aspx` 或 `.cshtml` 中輸入字元時,請問自己:「這行字會走哪條管道?」
原文出處:博客園 - ASP.NET WebForm頁面內容輸出方式