首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> .NET 實例教學

ASP.NET WebForm 頁面輸出機制深度解析:<%= %> vs <% %> vs Response.Write

     編輯:.NET 實例教學

前言:看似簡單的輸出,暗藏玄機

在 ASP.NET WebForm(含 MVC 預設視圖引擎)中,頁面輸出內容的方式不只一種:`<%= %>`、`<% %>`、`<%: %>`(Razor)、`Response.Write()`、`HtmlTextWriter` 等。它們最終都會寫入同一個 `HttpResponse.Output` 流,但執行時機、編碼處理、可測試性、架構合規性卻大相徑庭。本文深入剖析編譯後的 `Render` 方法,揭示輸出機制的本質差異。

頁面編譯本質:Render 方法與 HtmlTextWriter

.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("");
}

Response.Write() 的特殊性:繞過 HtmlTextWriter

<%= "Hello World" %>        // → writer.Write("Hello World")
<% Response.Write("Hello World"); %>  // → Response.Output.Write("Hello World")

**關鍵差異**:

  • `writer.Write()` 經過 `HtmlTextWriter`,可被控制項攔截、過濾、轉換(如 `HttpResponse.Filter`、行動裝置適配器)
  • `Response.Write()` 直接寫入 `Output` 流,**繞過所有輸出管道**,可能導致:
  1. 輸出順序錯亂(早於/晚於 `writer` 內容)
  2. 過濾器/壓縮/編碼模組失效
  3. 單元測試難以攔截驗證
  4. 違反「輸出集中化」架構原則

實務準則:何時用什麼?

✅ 推薦:<%= %> / <%: %> (Razor @)

  • 標準輸出,受管道控制,可測試,安全(`<%: %>` 自動編碼)

✅ 推薦:<% %> 僅用於流程控制

  • `if`、`foreach`、`using`、`var` 宣告等邏輯結構
  • 嚴禁在 `<% %>` 內直接 `Response.Write()`

❌ 避免:Response.Write()

  • 僅在 `HttpHandler`、自訂 `IHttpHandler`、舊版相容層等**無 HtmlTextWriter 可用**時使用
  • 現代 ASP.NET Core 中已無 `Response.Write()`,改用 `Response.WriteAsync()` 寫入 `HttpResponse.Body`

⚠️ 特例:Html.RenderPartial / Html.Partial (MVC)

  • `RenderPartial`:內部直接寫入 `ViewContext.Writer`(相當於 `writer.Write()`),**無回傳值**
  • `Partial`:回傳 `IHtmlString` / `HtmlString`,**由 `<%= %>` 或 `@` 輸出**,支援巢狀組合、單元測試
  • **現代建議**:優先使用 `Partial` / `ViewComponent` / `TagHelper`,避免 `RenderPartial` 的副作用式輸出

架構啟示:輸出管道的單一責任

ASP.NET WebForm 將「輸出」集中於 `HtmlTextWriter`,這是**管道模式**的體現:

  1. 所有輸出經過同一入口
  2. 可掛載過濾器(壓縮、最小化、安全編碼、行動適配)
  3. 可攔截測試(`StringWriter` 替換 `HtmlTextWriter`)
  4. 支援非同步刷新(`writer.Flush()`)

`Response.Write()` 打破了這個管道,屬於**反模式**。

結語

理解頁面輸出機制,不只是為了面試題,更是為了寫出**可維護、可測試、安全、架構合規**的視圖層代碼。下次在 `.aspx` 或 `.cshtml` 中輸入字元時,請問自己:「這行字會走哪條管道?」

原文出處:博客園 - ASP.NET WebForm頁面內容輸出方式
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved