理解 ASP.NET WebForm 頁面如何將內容輸出至 HTTP 回應,不僅是經典 WebForm 開發必修課,對採用預設 WebForm View Engine 的 ASP.NET MVC 專案同樣關鍵。本文從編譯後的類別結構切入,剖析 <%= %>、<% %>、伺服器控制項渲染的底層運作差異。
.aspx 頁面編譯為繼承 System.Web.UI.Page 的類別,核心邏輯在覆寫 Render(HtmlTextWriter writer) 方法:
public class MyPage : Page
{
protected override void Render(HtmlTextWriter writer)
{
// 所有輸出操作皆透過 writer 進行
writer.Write("");
// ... 靜態 HTML、程式碼塊、控制項渲染
writer.Write("");
}
}
| 標記 | 內容類型 | 編譯結果 | 適用場景 |
|---|---|---|---|
<%= expression %> |
運算式(無分號) | writer.Write(expression) |
輸出變數、屬性、方法回傳值 |
<% statement; %> |
陳述式(需分號) | 直接插入 Render 方法程式碼 | 流程控制、變數宣告、複雜邏輯 |
<%# Eval("Field") %> |
資料繫結運算式 | writer.Write(DataBinder.Eval(...)) |
Repeater/GridView/ListView 模板內 |
<%
var now = DateTime.Now;
if (now.Hour < 12) { %>
<h1>早安!</h1>
<% } else { %>
<h1>午安!</h1>
<% } %>
<p>現在時間:<%= now.ToString("HH:mm:ss") %></p>
編譯後相當於:
protected override void Render(HtmlTextWriter writer)
{
var now = DateTime.Now;
if (now.Hour < 12) {
writer.Write("早安!
");
} else {
writer.Write("午安!
");
}
writer.Write("現在時間:");
writer.Write(now.ToString("HH:mm:ss"));
writer.Write("
");
}
ControlCollection)Page.Render(writer) 進入遞迴渲染Render(HtmlTextWriter writer) 或 RenderContentsHtmlTextWriter → HttpResponse.OutputStreamASP.NET MVC 的 WebFormViewEngine 同樣將 .aspx/.ascx 編譯為 Page/Control,但:
<% %> 邏輯:提倡 View 只含呈現邏輯@Html.TextBoxFor(...) 內部同樣呼叫 writer.Write<% Html.RenderPartial("MyPartial"); %> // 直接寫入 writer(較快)
<%= Html.Partial("MyPartial") %> // 回傳字串再 Write(便於測試/快取)
| 做法 | 影響 | 建議 |
|---|---|---|
| 大量字串串接後一次 Write | 記憶體壓力大、GC 頻繁 | 直接多次 writer.Write 或使用 StringBuilder |
在 <% %> 中查詢資料庫 |
阻塞渲染管線、違反關注點分離 | 資料準備於 Action/Controller,View 僅呈現 |
| Response.Write 繞過 writer | 破壞輸出快取、過濾器管線 | 嚴禁使用,統一透過 writer |
public class MinifyHtmlWriter : HtmlTextWriter
{
public MinifyHtmlWriter(TextWriter writer) : base(writer) { }
public override void Write(string s)
{
// 移除多餘空白、換行(簡易版)
var minified = Regex.Replace(s, @"\s+", " ");
base.Write(minified);
}
}
// Global.asax
protected void Application_BeginRequest()
{
Response.Output = new MinifyHtmlWriter(Response.Output);
}
掌握輸出管線細節,能避免常見的亂碼、重複輸出、快取失效等疑難雜症,也能在需要時精準介入(如壓縮、最小化、簽章注入),是 ASP.NET 開發者的核心內功。