溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

精通MVC3摘譯(9)-過(guò)濾器

發(fā)布時(shí)間:2020-04-11 02:03:01 來(lái)源:網(wǎng)絡(luò) 閱讀:2192 作者:cnn237111 欄目:編程語(yǔ)言

Filter在請(qǐng)求管道注入額外的邏輯。他們提供簡(jiǎn)單優(yōu)雅的方法實(shí)現(xiàn)橫切點(diǎn)關(guān)注。這個(gè)術(shù)語(yǔ)指的是在穿越整個(gè)應(yīng)用程序中使用,而且不適合使用在任何單獨(dú)的地方,所以這會(huì)打破關(guān)注模式的分離。經(jīng)典的橫切點(diǎn)關(guān)注的例子比如日志,認(rèn)證,緩存。

Filter也被認(rèn)為是橫切點(diǎn)關(guān)注,因?yàn)檫@個(gè)術(shù)語(yǔ)在其他web application框架,包括Ruby也是實(shí)現(xiàn)同樣功能。然而MVC Framework Filter完全不同于ASP.NET 平臺(tái)的Request.Filter和Response.Filter對(duì)象。Request.Filter和Response.Filter對(duì)象在request和response流上執(zhí)行轉(zhuǎn)換。你可以在MVC application中使用Request.Filter 和Response.Filter,但是,通常當(dāng)ASP.NET MVC程序員談到filter時(shí),指的是接下要談的類型,在本文,我們會(huì)展示MVC Framework提供的filter不同的之類,如何創(chuàng)建使用filter,如何控制他們的執(zhí)行。

使用Filter

我們想要讓action方法只能由認(rèn)證過(guò)的用戶使用。我們可以在每個(gè)action方法檢查請(qǐng)求的認(rèn)證狀態(tài)。如下面的代碼,顯式的在action方法檢測(cè)認(rèn)證信息。

namespace SportsStore.WebUI.Controllers {

public class AdminController : Controller {

// ... instance variables and constructor

public ViewResult Index() {

if (!Request.IsAuthenticated) {

    FormsAuthentication.RedirectToLoginPage();

}

// ...rest of action method

}

public ViewResult Create() {

if (!Request.IsAuthenticated) {

FormsAuthentication.RedirectToLoginPage();

}

// ...rest of action method

}

public ViewResult Edit(int productId) {

if (!Request.IsAuthenticated) {

    FormsAuthentication.RedirectToLoginPage();

}

// ...rest of action method

}

// ... other action methods

}

}

可以看到這方法中有很多重復(fù)代碼,所以我們決定使用filter。如下代碼:

namespace SportsStore.WebUI.Controllers {

[Authorize]

public class AdminController : Controller {

// ... instance variables and constructor

public ViewResult Index() {

// ...rest of action method

}

public ViewResult Create() {

// ...rest of action method

}

public ViewResult Edit(int productId) {

// ...rest of action method

}

// ... other action methods

}

}

Filter是.NET特性,它是加在request處理管道上的額外步驟。上例中,我們使用Authorize filter,和之前那種重復(fù)檢查的方法,有相同的效果。

特性是從System.Attribute繼承的特殊的.NET類。你可以把它們附加到其它代碼上,包括類,方法,屬性,字段。目的就是在編譯的代碼中植入額外的信息,在運(yùn)行事情你就可以讀回它們。

C#中,特性使用的時(shí)候要加上方括號(hào),你能通過(guò)命名參數(shù)語(yǔ)法組合它們的公共屬性(比如,[MyAttribute(SomeProperty=value)])。在C#編譯器命名約定中,如果特性類以單詞Attribute結(jié)尾,你可以忽略這部分(比如,應(yīng)用AuthorizeAttribute時(shí),可以直接寫[Authorize])

Filter的四種基本類型

MVC Framework 支持四種不同的filter類型。每個(gè)都允許你在請(qǐng)求管道的不同點(diǎn)處引入自己的邏輯,下表列出了這四種類型。

精通MVC3摘譯(9)-過(guò)濾器

在MVC Framework調(diào)用action之前,它會(huì)檢查方法定義,查看實(shí)現(xiàn)了上述表格中的接口的特性是否存在。如果存在,那么在request管道的恰當(dāng)處,有這些接口定義的方法就會(huì)被調(diào)用。framework包括了實(shí)現(xiàn)filter接口的默認(rèn)的特性類。

注意ActionFilterAttribute類實(shí)現(xiàn)了IActionFilter和IResultFilter 接口。此類是抽象類,迫使你提供一個(gè)實(shí)現(xiàn)。其它類,AuthorizeAttribute和HandleErrorAttribute包含了有用的功能,可以不需要繼承直接使用。

在controller和action方法上應(yīng)用Filter

Filter可以應(yīng)用在單個(gè)action方法上,或者整個(gè)controller上,在上面的例子,我們把Authorize filter應(yīng)用于 AdminController類,這和應(yīng)用在每一個(gè)controller中的action方法有同樣的效果,如下:

namespace SportsStore.WebUI.Controllers {

public class AdminController : Controller {

// ... instance variables and constructor

[Authorize]

public ViewResult Index() {

if (!Request.IsAuthenticated) {

FormsAuthentication.RedirectToLoginPage();

}

// ...rest of action method

}

[Authorize]

public ViewResult Create() {

if (!Request.IsAuthenticated) {

FormsAuthentication.RedirectToLoginPage();

}

// ...rest of action method

}

// ... other action methods

}

}

你可以應(yīng)用多個(gè)filter,無(wú)論他們匹配到controller或者單個(gè)action方法。下面展示3種不同的使用filter的方法。

[Authorize(Roles="trader")] // applies to all actions

public class ExampleController : Controller {

[ShowMessage] // applies to just this action

[OutputCache(Duration=60)] // applies to just this action

public ActionResult Index() {

// ... action method body

}

}

注意,如果你為controller自定義了基類,那么任何應(yīng)用在基類上的filter也會(huì)應(yīng)用在子類上。

使用Authorization Filter

Authorization filter 是最先運(yùn)行的filter,它在其他filter和action方法之前被調(diào)用,就如它的命名,這些filter強(qiáng)迫你的認(rèn)證策略,確保action方法只能被認(rèn)證過(guò)的用戶調(diào)用。Authorization filter 實(shí)現(xiàn)IAuthorizationFilter 接口,如下代碼:

namespace System.Web.Mvc {

public interface IAuthorizationFilter {

void OnAuthorization(AuthorizationContext filterContext);

}

}

MVC Framework從瀏覽器收到一個(gè)請(qǐng)求,路由系統(tǒng)已經(jīng)處理了請(qǐng)求的URL,抽取了controller和action的名字。一個(gè)controller的實(shí)例創(chuàng)建,但是在action方法調(diào)用之前,MVC Framework檢查是否有任何authorization filter應(yīng)用在action方法。如果有,那么這個(gè)由IAuthorizationFilter接口定義的方法——OnAuthorization方法會(huì)被調(diào)用,如果authentication filter同意了請(qǐng)求,那么處理管道中下一步才會(huì)開始,否則請(qǐng)求就會(huì)拒絕。

創(chuàng)建Authentication Filter

理解authentication filter工作原理的最好方法就是創(chuàng)建一個(gè)。下面的代碼是一段簡(jiǎn)單的示例。它僅僅檢查用戶是否登錄了。(Request.IsAuthenticated是ture),同時(shí)username要出現(xiàn)在允許用戶列表中。

using System;

using System.Linq;

using System.Web.Mvc;

using System.Web;

namespace MvcFilters.Infrastructure.Filters {

public class CustomAuthAttribute : AuthorizeAttribute {

private string[] allowedUsers;

public CustomAuthAttribute(params string[] users) {

allowedUsers = users;

}

protected override bool AuthorizeCore(HttpContextBase httpContext) {

return httpContext.Request.IsAuthenticated &&

allowedUsers.Contains(httpContext.User.Identity.Name,

StringComparer.InvariantCultureIgnoreCase);

}

}

}

這個(gè)創(chuàng)建了一個(gè)authorization filter最簡(jiǎn)單的方法是繼承AuthorizeAttribute類,重寫AuthorizeCore方法。這確保了從AuthorizeAttribute內(nèi)建功能中獲益。

警告:編寫安全保障代碼是危險(xiǎn)行為

我們寫了一個(gè)自定義authorization filter的例子,因?yàn)槲覀冋J(rèn)為它可以展示filter的運(yùn)行方式,但是對(duì)于編寫自己安全代碼,我們要小心。這種技能很少有人會(huì)去使用,這會(huì)讓我們的應(yīng)用程序安全出現(xiàn)未考慮到的漏洞。

我們盡可能的使用那些廣泛使用,并且被實(shí)踐過(guò)的安全代碼,在這種情況下,MVC Framework提供了一個(gè)功能全面的authorization filter,可以通過(guò)繼承它來(lái)實(shí)現(xiàn)自定義認(rèn)證策略。我們盡可能使用它,并且我們建議你也這樣做,這樣,當(dāng)你的安全數(shù)據(jù)在網(wǎng)上泄露了,你至少可以罵微軟。

我們的filter構(gòu)造方法帶有一組名字的數(shù)組,這數(shù)組內(nèi)容是被認(rèn)證的用戶的信息。我們的filter包含一個(gè)PerformAuthenticationCheck方法,確保請(qǐng)求是認(rèn)證的,用戶也是在已認(rèn)證的集合中。這個(gè)類中有趣的部分是OnAuthorization方法的實(shí)現(xiàn)。傳給這個(gè)方法的參數(shù)是AuthorizationContext 類的一個(gè)實(shí)例,AuthorizationContext是繼承于ControllerContext的。ControllerContext 能使我們?cè)L問(wèn)一些有用的對(duì)象,不僅僅是HttpContextBase(通過(guò)HttpContextBase,我們可以訪問(wèn)request的細(xì)節(jié))。ControllerContext的屬性在下表中列出,所以這些用于不同的action filer的context 對(duì)象都繼承自這個(gè)類,所以你可以始終如一的使用這些屬性。

精通MVC3摘譯(9)-過(guò)濾器

當(dāng)我們想檢查是否請(qǐng)求被認(rèn)證了,我們就如下的寫法:

... filterContext.HttpContext.Request.IsAuthenticated ...

AuthorizationContext定義了2個(gè)額外的屬性,如下表:

精通MVC3摘譯(9)-過(guò)濾器

第一個(gè)屬性ActionDescriptor,返回一個(gè)System.Web.Mvc.ActionDescriptor實(shí)例,你可以通過(guò)這個(gè)屬性得到你應(yīng)用了filter的action的信息。第二個(gè)屬性,Result,是讓你filter工作的關(guān)鍵。如果你要對(duì)一個(gè)action方法認(rèn)證請(qǐng)求,那么你在OnAuthorization方法上不用做什么,MVC Framework認(rèn)為這個(gè)請(qǐng)求應(yīng)該處理。但是,如果你設(shè)置context對(duì)象的Result屬性為一個(gè)ActionResult對(duì)象,MVC

Framework將使用使用它作為整個(gè)請(qǐng)求的結(jié)果。管道中剩下的步驟則不會(huì)被運(yùn)行了,你提供的result會(huì)運(yùn)行輸出給用戶。

在我們的例子中,如果我們的PerformAuthenticationCheck返回false(表面整個(gè)請(qǐng)求沒有認(rèn)證通過(guò),或者用戶不是認(rèn)證用戶),然后我們創(chuàng)建一個(gè)HttpUnauthorizedResultaction result,然后制定context的 Result 屬性,如下:

filterContext.Result = new HttpUnauthorizedResult();

要使用我們的自定義authorization filter。我們只需要將特性放在action方法上,如下代碼:

...

[CustomAuth("adam", "steve", "bob")]

public ActionResult Index() {

return View();

}

...

使用內(nèi)建的認(rèn)證Filter

MVCFramework包含了一個(gè)實(shí)用的認(rèn)證filter,AuthorizeAttribute。我們可以使用兩個(gè)公共屬性指定認(rèn)證策略,如下:

精通MVC3摘譯(9)-過(guò)濾器

...

[Authorize(Users="adam, steve, bob", Roles="admin")]

public ActionResult Index() {

return View();

}

...

上例中,我們指定了用戶和權(quán)限。這意味著只有當(dāng)用戶和權(quán)限同時(shí)滿足的情況下才認(rèn)證系統(tǒng)才會(huì)通過(guò)。這里還有一個(gè)隱式的條件,就是這個(gè)請(qǐng)求必須是被認(rèn)證的。如果我們不指定任何用戶和權(quán)限,那么任何用戶都可使用此action方法。

對(duì)大多數(shù)應(yīng)用程序來(lái)說(shuō),AuthorizeAttribute提供的認(rèn)證策略已經(jīng)足夠了。如果你需要實(shí)現(xiàn)一些特殊的功能,你可以繼承這個(gè)類。直接實(shí)現(xiàn)IAuthorizationFilter接口風(fēng)險(xiǎn)比較小,但是你應(yīng)該仔細(xì)思考,你的策慮所帶來(lái)的影響,而且要徹底的測(cè)試。

AuthorizeAttribute類提供2個(gè)不同方法。

AuthorizeCore方法,由AuthorizeAttribute的OnAuthorization調(diào)用,實(shí)現(xiàn)認(rèn)證檢查。

HandleUnauthorizedRequest 方法,當(dāng)認(rèn)證檢查失敗的時(shí)候調(diào)用。

實(shí)現(xiàn)自定義認(rèn)證失敗策略

默認(rèn)的處理認(rèn)證失敗的策略是定向到用戶登錄頁(yè)面。我們不總希望如此。比如,如果使用ajax,發(fā)送重定向肯能會(huì)讓用戶在頁(yè)面中間看到一個(gè)登錄頁(yè)面。幸運(yùn)的是,我們可以重寫AuthorizeAttribute類的HandleUnauthorizedRequest方法來(lái)創(chuàng)建一個(gè)自定義策略。

下面的例子實(shí)現(xiàn)了自定義認(rèn)證失敗的策略:

using System.Web.Mvc;

namespace MvcFilters.Infrastructure.Filters {

public class AjaxAuthorizeAttribute : AuthorizeAttribute {

protected override void HandleUnauthorizedRequest(AuthorizationContext context) {

if (context.HttpContext.Request.IsAjaxRequest()) {

UrlHelper urlHelper = new UrlHelper(context.RequestContext);

context.Result = new JsonResult {

Data = new {

Error = "NotAuthorized",

LogOnUrl = urlHelper.Action("LogOn", "Account")

}, JsonRequestBehavior = JsonRequestBehavior.AllowGet};

} else {

base.HandleUnauthorizedRequest(context);

}

}

    }

}

當(dāng)Filter發(fā)現(xiàn)是ajax請(qǐng)求,就會(huì)按照J(rèn)SON數(shù)據(jù)的方式響應(yīng)。正常的請(qǐng)求還是由基類中默認(rèn)的策略處理,ajax客戶端必須也要寫響應(yīng)的代碼響應(yīng)。

使用Exception Filters

Exception filters只有在運(yùn)行action方法拋出異常的時(shí)候才會(huì)運(yùn)行。這個(gè)異??赡軓囊韵聨讉€(gè)地方拋出:

其他類型的filter(認(rèn)證,action,result filter)

action方法自身

當(dāng)action結(jié)果運(yùn)行后。

創(chuàng)建Exception Filter

Exception filters必須實(shí)現(xiàn)IExceptionFilter接口,接口如下:

namespace System.Web.Mvc {

public interface IExceptionFilter {

void OnException(ExceptionContext filterContext);

}

}

OnException方法在拋出異常的時(shí)候調(diào)用。參數(shù)是ExceptionContext。這個(gè)類和認(rèn)證filter的參數(shù)類似,也是繼承自ControllerContext類。所以你可以獲得request信息,并且定義一下額外的指定的filter屬性,這些屬性如下表:

精通MVC3摘譯(9)-過(guò)濾器

exception filter的Result屬性是告訴MVC Framework要做什么。兩個(gè)主要的用處是記錄異常和顯示恰當(dāng)?shù)南⒔o用戶。下例顯示了一個(gè)演示,當(dāng)特殊的未處理異常發(fā)生時(shí),就會(huì)跳轉(zhuǎn)到一個(gè)指定的錯(cuò)誤頁(yè)面

using System.Web.Mvc;

using System;

namespace MvcFilters.Infrastructure.Filters {

public class MyExceptionAttribute: FilterAttribute, IExceptionFilter {

public void OnException(ExceptionContext filterContext) {

if (!filterContext.ExceptionHandled &&

filterContext.Exception is NullReferenceException) {

filterContext.Result = new RedirectResult("/SpecialErrorPage.html");

filterContext.ExceptionHandled = true;

            }

    }

}

}

filter回應(yīng)NullReferenceException實(shí)例,而且僅當(dāng)沒有其他exception filter指示處理了異常才發(fā)生。我們把用戶重定向到一個(gè)錯(cuò)誤頁(yè)面,如下代碼

...

[MyException]

public ActionResult Index() {

...

如果Index action方法拋出異常,是一個(gè)NullReferenceException,而且沒有其他 exception filter處理這一個(gè)異常,那么我們的filter將重定向到SpecialErrorPage.html。

使用內(nèi)建的Exception Filter

HandleErrorAttribute是 IExceptionFilter 接口一個(gè)實(shí)現(xiàn),它使得創(chuàng)建exception filter更簡(jiǎn)單。你可以通過(guò)下面的屬性指定異常和view和layout的名字,從而指定一個(gè)異常,如下所示:

精通MVC3摘譯(9)-過(guò)濾器

當(dāng)一個(gè)未處理的類型異常出現(xiàn)是,filter會(huì)把HTTP result code設(shè)置為500,意思是服務(wù)器錯(cuò)誤,同時(shí)顯示用戶通過(guò)View屬性指定的view(通過(guò)Master使用layout),下面的例子展示了如何使用HandleErrorAttribute filter

[HandleError(ExceptionType=typeof(NullReferenceException), View="SpecialError")]

public ActionResult Index() {

...

上述例子,我們對(duì)NullReferenceException類型感興趣,希望出現(xiàn)異常時(shí)顯示SpecialErrorView

注意,The HandleErrorAttribute filter 僅在Web.config中自定義error是enabled的情況下工作。比如,在<system.web>節(jié)點(diǎn)增加節(jié)點(diǎn) <customErrors mode="On" />。默認(rèn)的自定義error模式是RemoteOnly,意味著在開發(fā)期間,HandleErrorAttribute將不攔截異常,但是當(dāng)你部署產(chǎn)品服務(wù)器,并且從其他電腦上獲得請(qǐng)求,HandleErrorAttribute就會(huì)采取行動(dòng)了,要想了解終端用戶所看到的,必須確保把自定義error mode設(shè)置為On。

當(dāng)呈現(xiàn)一個(gè)view時(shí),HandleErrorAttribute filter傳遞一個(gè)HandleErrorInfo view model對(duì)象,你可以在消息中包含異常的細(xì)節(jié),展示給用戶。如下例子,當(dāng)現(xiàn)實(shí)錯(cuò)誤信息時(shí),使用View Model對(duì)象:

@Model HandleErrorInfo

@{

    ViewBag.Title = "Sorry, there was a problem!";

}

<p>

There was a <b>@Model.Exception.GetType().Name</b>

while rendering <b>@Model.ControllerName</b>'s

<b>@Model.ActionName</b> action.

</p>

<p>

The exception message is: <b><@Model.Exception.Message></b>

</p>

<p>Stack trace:</p>

<pre>@Model.Exception.StackTrace</pre>

效果圖如下:

精通MVC3摘譯(9)-過(guò)濾器

使用Action和Result Filter

Action和Result Filter是常用的filter,可以用于任何目的。它們都遵循一個(gè)公共模式。內(nèi)建的類創(chuàng)建filter,IActionFilter的類型,實(shí)現(xiàn)全部的接口。接口如下:

namespace System.Web.Mvc {

public interface IActionFilter {

void OnActionExecuting(ActionExecutingContext filterContext);

void OnActionExecuted(ActionExecutedContext filterContext);

    }

}

此接口定義了2個(gè)方法,MVC Framework 在action方法調(diào)用之前,先調(diào)用OnActionExecutin方法。在action方法調(diào)用之后,調(diào)用OnActionExecuted方法。

實(shí)現(xiàn)OnActionExecuting方法

The OnActionExecuting 方法在action方法在action方法調(diào)用之前先調(diào)用。你可以通過(guò)這個(gè)來(lái)檢查請(qǐng)求,選擇取消請(qǐng)求,修改請(qǐng)求,或者啟動(dòng)另一個(gè)活動(dòng)跨越action的調(diào)用。此方法的參數(shù)是一個(gè)ActionExecutingContext ,是ControllerContext的子類,有2個(gè)同樣的屬性,和你在其他context對(duì)象中看到的一樣。詳細(xì)描述如下表:

精通MVC3摘譯(9)-過(guò)濾器

你可以有選擇的通過(guò)設(shè)置parameter的result屬性來(lái)取消請(qǐng)求,如下演示代碼:

namespace MvcFilters.Infrastructure.Filters {

    public class MyActionFilterAttribute : FilterAttribute, IActionFilter {

    public void OnActionExecuting(ActionExecutingContext filterContext) {

    if (!filterContext.HttpContext.Request.IsSecureConnection) {

        filterContext.Result = new HttpNotFoundResult();

    }

}

public void OnActionExecuted(ActionExecutedContext filterContext) {

// do nothing

}

}

}

此例中,使用OnActionExecuting方法檢查請(qǐng)求是否是SSL的,如果不是,返回404-Not Found響應(yīng)給用戶。

注意,如上例所示,你不需要將IActionFilter接口中的方法都實(shí)現(xiàn),如果你不需要加任何邏輯,就置空。消息不要拋出NotImplementedException異常,因?yàn)槿绻氵@樣做,exception filter就會(huì)被執(zhí)行。

實(shí)現(xiàn)OnActionExecuted方法

你也可以使用filter去執(zhí)行一些任務(wù),跨越執(zhí)行action方法。下面是一個(gè)簡(jiǎn)單的例子計(jì)算action方法執(zhí)行的時(shí)間開銷。

using System.Diagnostics;

using System.Web.Mvc;

namespace MvcFilters.Infrastructure.Filters {

public class ProfileAttribute : FilterAttribute, IActionFilter {

private Stopwatch timer;

public void OnActionExecuting(ActionExecutingContext filterContext) {

timer = Stopwatch.StartNew();

}

public void OnActionExecuted(ActionExecutedContext filterContext) {

timer.Stop();

if (filterContext.Exception == null) {

filterContext.HttpContext.Response.Write(

string.Format("Action method elapsed time: {0}",

timer.Elapsed.TotalSeconds));

        }

}

}

}

此例中,我們使用OnActionExecuting方法,啟動(dòng)一個(gè)計(jì)數(shù)器。當(dāng)action方法完成后,OnActionExecuted方法調(diào)用。然后我們停止計(jì)時(shí)器,寫出響應(yīng),輸出所花的時(shí)間。結(jié)果圖如下:

精通MVC3摘譯(9)-過(guò)濾器

傳遞給OnActionExecuted方法的參數(shù)是一個(gè)ActionExecutedContext對(duì)象。此類定義了一些額外的屬性,如下表。Exception屬性返回任何action方法拋出的異常,ExceptionHandled屬性指示了是否有其他filter處理了它。

精通MVC3摘譯(9)-過(guò)濾器

屬性Canceled,如果其他filter cancel了一個(gè)請(qǐng)求(通過(guò)設(shè)置result屬性的值),那么返回true。但我們的OnActionExecuted方法仍然調(diào)用,只有這樣我們才能是否使用的資源。

實(shí)現(xiàn)Result Filter

Action filters和result filters有一些共同點(diǎn). Result filters對(duì)于action results 就好比action filters

對(duì)于action methods. Result filters 實(shí)現(xiàn)IResultFilter 接口, 接口代碼如下:

namespace System.Web.Mvc {

public interface IResultFilter {

void OnResultExecuting(ResultExecutingContext filterContext);

void OnResultExecuted(ResultExecutedContext filterContext);

}

}

之前,我們說(shuō)過(guò)action方法如何返回action result。這運(yùn)行我們分離action的意圖和執(zhí)行。當(dāng)我們應(yīng)用一個(gè)result filter到action方法上,一旦action方法返回action result,OnResultExecuting方法就被調(diào)用,但是在action result執(zhí)行之前 。OnResultExecuted方法在action result執(zhí)行后調(diào)用。這些方法的參數(shù)分別是ResultExecutingContext 和ResultExecutedContext 對(duì)象,它們和action filter的那部分非常相似。它們有相同的屬性,相同的效果。下例代碼展示了一個(gè)簡(jiǎn)單的 result filter的例子。

using System.Diagnostics;

using System.Web.Mvc;

namespace MvcFilters.Infrastructure.Filters {

public class ProfileResultAttribute : FilterAttribute, IResultFilter {

private Stopwatch timer;

public void OnResultExecuting(ResultExecutingContext filterContext) {

timer = Stopwatch.StartNew();

}

public void OnResultExecuted(ResultExecutedContext filterContext) {

timer.Stop();

filterContext.HttpContext.Response.Write(

string.Format("Result execution - elapsed time: {0}",

timer.Elapsed.TotalSeconds));

}

}

}

這個(gè)filter計(jì)算了執(zhí)行result所需要的時(shí)間。把這個(gè)filter附加的action方法上。

...

[ProfileResult]

public ActionResult Index() {

return View();

}

...

現(xiàn)在我們轉(zhuǎn)到action方法,輸出的內(nèi)容如下。

精通MVC3摘譯(9)-過(guò)濾器

注意,從filter中獲得的性能信息出現(xiàn)在頁(yè)面底部。這是因?yàn)槲覀冊(cè)?action result 執(zhí)行后——也就是view已經(jīng)呈現(xiàn)了,才寫下我們的消息。我們先前的filte在action result執(zhí)行之前寫到response的,因此它出現(xiàn)在page的頂部。

使用內(nèi)建的Action和Result Filter類

MVC Framework 包含了一個(gè)內(nèi)建的類,可以創(chuàng)建action 和result filters.

但是不像內(nèi)建的authorization 和exception filter, 它不提供任何有用的細(xì)節(jié). 這個(gè)類是ActionFilterAttribute 代碼如下:

public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter{

public virtual void OnActionExecuting(ActionExecutingContext filterContext) {

}

public virtual void OnActionExecuted(ActionExecutedContext filterContext) {

}

public virtual void OnResultExecuting(ResultExecutingContext filterContext) {

}

public virtual void OnResultExecuted(ResultExecutedContext filterContext) {

}

    }

}

使用這個(gè)類的好處就是你不需要實(shí)現(xiàn)你用不到的方法。如下例子,展示了繼承ActionFilterAttribute的filter,使用action方法和action result執(zhí)行,合并了我們的性能測(cè)量。

using System.Diagnostics;

using System.Web.Mvc;

namespace MvcFilters.Infrastructure.Filters {

public class ProfileAllAttribute : ActionFilterAttribute {

private Stopwatch timer;

public override void OnActionExecuting(ActionExecutingContext filterContext)

{

timer = Stopwatch.StartNew();

}

public override void OnActionExecuted(ActionExecutedContext filterContext)

{

timer.Stop();

filterContext.HttpContext.Response.Write(

string.Format("Action method elapsed time: {0}",

timer.Elapsed.TotalSeconds));

}

public override void OnResultExecuting(ResultExecutingContext filterContext)

{

timer = Stopwatch.StartNew();

}

public override void OnResultExecuted(ResultExecutedContext filterContext)

{

timer.Stop();

filterContext.HttpContext.Response.Write(

string.Format("Action result elapsed time: {0}",

timer.Elapsed.TotalSeconds));

}

}

}

ActionFilterAttribute 類實(shí)現(xiàn)了IActionFilter 和IResultFilter 接口,意味著MVC Framework把這個(gè)繼承類看作兩種filter類型, 即使并不是所有的方法都被重寫。如果我們?cè)谏鲜龅睦討?yīng)用這個(gè)filter到action方法,我們的輸出就如下:

精通MVC3摘譯(9)-過(guò)濾器

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI