Action 過濾器在代碼中體現為添加到Action上方的屬性,MVC架構套件含了一些過濾器,如:
OutputCache –指示Controller在指定時間內緩衝返回的結果。
HandleError –處理Contrller中Action拋出的異常
Authorize – 約束特定使用者或角色對Action的訪問
另外你還可以自己定義過濾器,比如:你想使用自訂的驗證機制;你想修改Action返回的資料等等。
使用Action 過濾器
Action 過濾器不僅可以控制單個Action,也可以控制整個Contrller。同時,一個Action可以應用多個過濾器。比如:
public class DataController : Controller
{
[OutputCache(Duration=10)]
public string Index()
{
return DateTime.Now.ToString("T");
}
}
這個Action返回了目前時間,但是你若在10秒鐘內重新整理介面,你會一直得到同一個值,因為這裡使用了OutputCache(Duration=10)。
過濾器的類型
ASP.NET MVC 架構支援以下幾種過濾器:
1、Authorization 過濾器– 實現了 IAuthorizationFilter 介面。這一類的過濾器用來實現使用者驗證和對Action的訪問授權。比如Authorize 就屬於Authorization 過濾器。
2、Action 過濾器– 實現了 IActionFilter 介面。它可以包含一些Action執行前或者執行後的邏輯,比如有一些過濾器專門用來修改Action返回的資料。
3、Result 過濾器– 實現了 IResultFilter 介面。它可以包含一些view result產生前或者產生後的邏輯,比如有一些過濾器專門用來修改視圖向瀏覽器展現前的結果。
4、Exception 過濾器– 實現了IExceptionFilter 介面。它用以用來處理Action或者Result的錯誤,也可以記錄錯誤。
過濾器的預設執行順序也和上面的列表相同,比如Authorization 過濾器會先於Action 過濾器執行,而Exception 過濾器總會在最後執行。當然你也可以根據需要通過Order屬性設定過濾器執行的順序。
自訂過濾器
自訂過濾器必須繼承System.Web.Mvc.FilterAttribute ,並且實現上述幾個介面中的一個或者多個。MVC架構為了方便開發人員,預定義了一個ActionFilterAttribute 類,它已實現了IActionFilter 和IResultFilter 介面。你可以重載ActionFilterAttribute 類中以下幾個方法:
OnActionExecuting – 在Action執行之前調用。
OnActionExecuted – 在Action執行之後調用。
OnResultExecuting – 在Result產生之前調用。
OnResultExecuted – 在Result產生之前調用。
下面樣本一個類:
Code
public class LogActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Log("OnActionExecuting", filterContext.RouteData);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
Log("OnActionExecuted", filterContext.RouteData);
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
Log("OnResultExecuting", filterContext.RouteData);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
Log("OnResultExecuted", filterContext.RouteData);
}
private void Log(string methodName, RouteData routeData)
{
var controllerName = routeData.Values["controller"];
var actionName = routeData.Values["action"];
var message = String.Format("{0} controller:{1} action:{2}", methodName, controllerName, actionName);
Debug.WriteLine(message, "Action Filter Log");
}
}
將LogActionFilter冠在某一個Action或者Controller上,就會列印對應Action的執行情況。如:
[LogActionFilter]
public class HomeController : Controller
{}
OutputCache過濾器
你可以使用OutputCache過濾器來緩衝的你查詢結果,這樣可以提高使用者體驗,也可以減少查詢次數。它有以下屬性:
Duration:緩衝的時間,以秒為單位,理論上緩衝時間可以很長,但實際上當系統資源緊張時,緩衝空間還是會被系統收回。
VaryByParam:以哪個欄位為標識來快取資料,比如當“ID”欄位變化時,需要改變緩衝(仍可保留原來的緩衝),那麼應該設VaryByParam為"ID"。這裡你可以設定以下幾個值:
* = 任何參數變化時,都改變緩衝。
none = 不改變緩衝。
以分號“;”為間隔的欄位名列表 = 列表中的欄位發生變化,則改變緩衝。
Location:快取資料放在何處。緩衝位置很重要,如果存在伺服器上,那麼所有使用者看到的緩衝視圖都會一樣,如果存在用戶端,那麼使用者只會看到自己的緩衝。比如:如果是一些私人資訊,那就不能存在伺服器上。你可以設定以下值:
· Any :預設值,輸出緩衝可位於產生請求的瀏覽器用戶端、參與請求的Proxy 伺服器(或任何其他伺服器)或處理請求的伺服器上。
· Client:輸出緩衝位於產生請求的瀏覽器用戶端上。
· Downstream 輸出緩衝可儲存在任何 HTTP 1.1 可緩衝裝置中,原始伺服器除外。這包括Proxy 伺服器和發出請求的用戶端。
· Server:輸出緩衝位於處理請求的 Web 服務器上。
· None:對於請求的頁,禁用輸出緩衝。
· ServerAndClient:輸出緩衝只能儲存在原始伺服器或發出請求的用戶端中。Proxy 伺服器不能緩衝響應。
NoStore:該屬性定義一個布爾值,用於決定是否阻止敏感資訊的二級儲存。
除了直接在Action或者類的定義前加上屬性,也可以使用設定檔,這樣就可以動態配置你的緩衝模式了。
在<system.web>節中,添加如下配置:
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="Cache1Hour" duration="3600" varyByParam="none"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
那麼在Controller中可以這樣使用:
[OutputCache(CacheProfile="Cache1Hour")]
public string Index()
{
return DateTime.Now.ToString("T");
}
[擴充]在已經緩衝的頁面上添加動態內容
為了提高使用者體驗,我們會使用緩衝技術,但是有時我們會需要在頁面上改變內容,如:提供一些動態資訊、廣告的變化等。
此時我們可以調用 HttpResponse.WriteSubstitution() 方法。
例如:
<% Response.WriteSubstitution(News.RenderNews); %>
其中News.RenderNews是一個靜態方法,它的定義如下,這個方法用來隨機顯示三條廣告詞。
Code
public class News
{
public static string RenderNews(HttpContext context)
{
var news = new List<string>
{
"Gas prices go up!",
"Life discovered on Mars!",
"Moon disappears!"
};
var rnd = new Random();
return news[rnd.Next(news.Count)];
}
}
你甚至可以為Response.WriteSubstitution()方法擴充一個Helper方法,如下所示:
Code
public static class AdHelper
{
public static void RenderBanner(this HtmlHelper helper)
{
var context = helper.ViewContext.HttpContext;
context.Response.WriteSubstitution(RenderBannerInternal);
}
private static string RenderBannerInternal(HttpContext context)
{
var ads = new List<string>
{
"/ads/banner1.gif",
"/ads/banner2.gif",
"/ads/banner3.gif"
};
var rnd = new Random();
var ad = ads[rnd.Next(ads.Count)];
return String.Format("<img src='{0}' />", ad);
}
}
那麼你就可以在頁面上如此調用:
<% Html.RenderBanner(); %>
這樣就會每重新整理一次頁,改變一次映像。但是資料內容卻還是緩衝的,並不會因為你重新整理了頁面而重新查詢資料庫。