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,分別是:
-
StripViewStateStream
運用 Regular Expression 技巧將所有 ViewState 相關標籤全部消除
-
StripNamingContainerStream
將所有包含有 NamingContainer 的多餘名稱全部移除
-
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">
protected void Page_Init(object sender, EventArgs e)
{
Response.Filter = new StripNamingContainerStream(Response.Filter);
}
</script>
其實除了 Response.Filter 屬性外,還有一個 Request.Filter 屬性,用法完全一樣,可以讓你過濾所有經由 HTTP Post 進來的 Stream 資料 ( HTTP Request Body )。
相關連結