The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

介紹一個 ASP.NET 裡鮮為人知的 Response.Filter 屬性

ASP.NET 有一個鮮為人知也很少人使用的 Response.Filter 屬性,Response.Filter 屬性本身是一個 Stream 型別,所以可以利用 Stream 的特性,將 Response.Filter 傳給下一個 Stream 進行資料處理。換句話說,你就可以透過繼承自 Stream 的自訂型別去修改 Response.Filter 傳入的資料,並且將資料進行修正動作。

之前很早就知道有這個屬性存在,但一直沒時間研究,今天趁假日把玩了一下,感覺還不賴,發現運用這個開發技巧可發揮的領域可多了,為了讓各位有點感覺,我先秀幾段程式碼展示威力:

Response.Filter = new GZipStream(Response.Filter, CompressionMode.Compress);    
Response.AppendHeader("Content-Encoding", "gzip");

以上程式碼可以放在 Page_Init 事件裡,最主要的功能就在於他將 Response.Filter 屬性先傳入一個 GZipStream 類別中,讓所有頁面輸出的 Stream 都會經過 GZipStream 壓縮,最後再新增一個回應標頭,告知瀏覽器此頁回應的資料是透過 gzip 壓縮過的。

另外,如果你要將每個輸出的頁面自動將多餘的空白濾掉,也可以運用 Response.Filter 的技巧,有興趣的人可以參考 Removing White Chars from ASP.NET Output using Response.Filter property 這篇文章。

在我前幾天寫的 ASP.NET MVC 開發心得分享 (3):與 WebForm 共舞 文章中,就有提到如何透過 jQuery 將 ViewState 相關的隱藏欄位刪除,不過若是透過 Response.Filter 屬性的應用將會更完美,而我今天就是用這個例子來練習應用 Response.Filter 屬性的。

我今天寫了一個 HttpModule 專案用來對所有 ASP.NET MVC 頁面進行過濾動作,效果感覺還不錯。另外,今天也心血來潮跑去 CodePlex 建立一個新專案,並將今天寫的專案與原始碼都上傳上去了,有興趣的人可以到 ASP.NET MVC Friendly HttpModule 下載。

這個專案包含兩個 Stream 類別與一個 HttpModule,分別是:

  1. StripViewStateStream
    運用 Regular Expression 技巧將所有 ViewState 相關標籤全部消除
  2. StripNamingContainerStream
    將所有包含有 NamingContainer 的多餘名稱全部移除
  3. MvcFriendlyModule
    在 BeginRequest 事件裡要定義 Response.Filter 屬性需套用的 Stream 類別

MvcFriendlyModule 中主要程式如下,可以一次套用兩個自訂的 Stream 類別:

void context_BeginRequest(object sender, EventArgs e)
{
    HttpApplication app = (HttpApplication)sender;

    if (app.Context.Response.ContentType == "text/html")
    {
        app.Context.Response.Filter =
            new StripNamingContainerStream(
                new StripViewStateStream(
                    app.Context.Response.Filter
                )
            );
    }
}

若你下載下載之後只要將 dll 加入到你現有的 ASP.NET MVC 專案,定設定網站的 web.config 加入 MvcFriendlyModule 模組即安裝完畢。

<httpModules>
    ....
    <add name="MvcFriendlyModule"
         type="MvcFriendlyModule.MvcFriendlyModule, MvcFriendlyModule"/>
    ....
</httpModules>

除了直接套用 HttpModule 到全網站之外,你也可以僅套用在單一網頁中,也可以只單套用其中一個 Stream 就好。例如在 ViewPage 中可以寫在 Page_Init 事件中:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
         Inherits="System.Web.Mvc.ViewPage" %>
<%@ Import Namespace="MvcFriendlyModule" %>
<script runat="server">
   1:  
   2:     protected void Page_Init(object sender, EventArgs e)
   3:     {
   4:         Response.Filter = new StripNamingContainerStream(Response.Filter);
   5:     }
</script>

其實除了 Response.Filter 屬性外,還有一個 Request.Filter 屬性,用法完全一樣,可以讓你過濾所有經由 HTTP Post 進來的 Stream 資料 ( HTTP Request Body )。

相關連結