中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發布時間:2020-04-11 02:03:01 來源:網絡 閱讀:2199 作者:cnn237111 欄目:編程語言

Filter在請求管道注入額外的邏輯。他們提供簡單優雅的方法實現橫切點關注。這個術語指的是在穿越整個應用程序中使用,而且不適合使用在任何單獨的地方,所以這會打破關注模式的分離。經典的橫切點關注的例子比如日志,認證,緩存。

Filter也被認為是橫切點關注,因為這個術語在其他web application框架,包括Ruby也是實現同樣功能。然而MVC Framework Filter完全不同于ASP.NET 平臺的Request.Filter和Response.Filter對象。Request.Filter和Response.Filter對象在request和response流上執行轉換。你可以在MVC application中使用Request.Filter 和Response.Filter,但是,通常當ASP.NET MVC程序員談到filter時,指的是接下要談的類型,在本文,我們會展示MVC Framework提供的filter不同的之類,如何創建使用filter,如何控制他們的執行。

使用Filter

我們想要讓action方法只能由認證過的用戶使用。我們可以在每個action方法檢查請求的認證狀態。如下面的代碼,顯式的在action方法檢測認證信息。

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

}

}

可以看到這方法中有很多重復代碼,所以我們決定使用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,和之前那種重復檢查的方法,有相同的效果。

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

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

Filter的四種基本類型

MVC Framework 支持四種不同的filter類型。每個都允許你在請求管道的不同點處引入自己的邏輯,下表列出了這四種類型。

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

在MVC Framework調用action之前,它會檢查方法定義,查看實現了上述表格中的接口的特性是否存在。如果存在,那么在request管道的恰當處,有這些接口定義的方法就會被調用。framework包括了實現filter接口的默認的特性類。

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

在controller和action方法上應用Filter

Filter可以應用在單個action方法上,或者整個controller上,在上面的例子,我們把Authorize filter應用于 AdminController類,這和應用在每一個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

}

}

你可以應用多個filter,無論他們匹配到controller或者單個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自定義了基類,那么任何應用在基類上的filter也會應用在子類上。

使用Authorization Filter

Authorization filter 是最先運行的filter,它在其他filter和action方法之前被調用,就如它的命名,這些filter強迫你的認證策略,確保action方法只能被認證過的用戶調用。Authorization filter 實現IAuthorizationFilter 接口,如下代碼:

namespace System.Web.Mvc {

public interface IAuthorizationFilter {

void OnAuthorization(AuthorizationContext filterContext);

}

}

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

創建Authentication Filter

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

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);

}

}

}

這個創建了一個authorization filter最簡單的方法是繼承AuthorizeAttribute類,重寫AuthorizeCore方法。這確保了從AuthorizeAttribute內建功能中獲益。

警告:編寫安全保障代碼是危險行為

我們寫了一個自定義authorization filter的例子,因為我們認為它可以展示filter的運行方式,但是對于編寫自己安全代碼,我們要小心。這種技能很少有人會去使用,這會讓我們的應用程序安全出現未考慮到的漏洞。

我們盡可能的使用那些廣泛使用,并且被實踐過的安全代碼,在這種情況下,MVC Framework提供了一個功能全面的authorization filter,可以通過繼承它來實現自定義認證策略。我們盡可能使用它,并且我們建議你也這樣做,這樣,當你的安全數據在網上泄露了,你至少可以罵微軟。

我們的filter構造方法帶有一組名字的數組,這數組內容是被認證的用戶的信息。我們的filter包含一個PerformAuthenticationCheck方法,確保請求是認證的,用戶也是在已認證的集合中。這個類中有趣的部分是OnAuthorization方法的實現。傳給這個方法的參數是AuthorizationContext 類的一個實例,AuthorizationContext是繼承于ControllerContext的。ControllerContext 能使我們訪問一些有用的對象,不僅僅是HttpContextBase(通過HttpContextBase,我們可以訪問request的細節)。ControllerContext的屬性在下表中列出,所以這些用于不同的action filer的context 對象都繼承自這個類,所以你可以始終如一的使用這些屬性。

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

當我們想檢查是否請求被認證了,我們就如下的寫法:

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

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

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

第一個屬性ActionDescriptor,返回一個System.Web.Mvc.ActionDescriptor實例,你可以通過這個屬性得到你應用了filter的action的信息。第二個屬性,Result,是讓你filter工作的關鍵。如果你要對一個action方法認證請求,那么你在OnAuthorization方法上不用做什么,MVC Framework認為這個請求應該處理。但是,如果你設置context對象的Result屬性為一個ActionResult對象,MVC

Framework將使用使用它作為整個請求的結果。管道中剩下的步驟則不會被運行了,你提供的result會運行輸出給用戶。

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

filterContext.Result = new HttpUnauthorizedResult();

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

...

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

public ActionResult Index() {

return View();

}

...

使用內建的認證Filter

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

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

...

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

public ActionResult Index() {

return View();

}

...

上例中,我們指定了用戶和權限。這意味著只有當用戶和權限同時滿足的情況下才認證系統才會通過。這里還有一個隱式的條件,就是這個請求必須是被認證的。如果我們不指定任何用戶和權限,那么任何用戶都可使用此action方法。

對大多數應用程序來說,AuthorizeAttribute提供的認證策略已經足夠了。如果你需要實現一些特殊的功能,你可以繼承這個類。直接實現IAuthorizationFilter接口風險比較小,但是你應該仔細思考,你的策慮所帶來的影響,而且要徹底的測試。

AuthorizeAttribute類提供2個不同方法。

AuthorizeCore方法,由AuthorizeAttribute的OnAuthorization調用,實現認證檢查。

HandleUnauthorizedRequest 方法,當認證檢查失敗的時候調用。

實現自定義認證失敗策略

默認的處理認證失敗的策略是定向到用戶登錄頁面。我們不總希望如此。比如,如果使用ajax,發送重定向肯能會讓用戶在頁面中間看到一個登錄頁面。幸運的是,我們可以重寫AuthorizeAttribute類的HandleUnauthorizedRequest方法來創建一個自定義策略。

下面的例子實現了自定義認證失敗的策略:

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);

}

}

    }

}

當Filter發現是ajax請求,就會按照JSON數據的方式響應。正常的請求還是由基類中默認的策略處理,ajax客戶端必須也要寫響應的代碼響應。

使用Exception Filters

Exception filters只有在運行action方法拋出異常的時候才會運行。這個異常可能從以下幾個地方拋出:

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

action方法自身

當action結果運行后。

創建Exception Filter

Exception filters必須實現IExceptionFilter接口,接口如下:

namespace System.Web.Mvc {

public interface IExceptionFilter {

void OnException(ExceptionContext filterContext);

}

}

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

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

exception filter的Result屬性是告訴MVC Framework要做什么。兩個主要的用處是記錄異常和顯示恰當的消息給用戶。下例顯示了一個演示,當特殊的未處理異常發生時,就會跳轉到一個指定的錯誤頁面

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回應NullReferenceException實例,而且僅當沒有其他exception filter指示處理了異常才發生。我們把用戶重定向到一個錯誤頁面,如下代碼

...

[MyException]

public ActionResult Index() {

...

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

使用內建的Exception Filter

HandleErrorAttribute是 IExceptionFilter 接口一個實現,它使得創建exception filter更簡單。你可以通過下面的屬性指定異常和view和layout的名字,從而指定一個異常,如下所示:

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

當一個未處理的類型異常出現是,filter會把HTTP result code設置為500,意思是服務器錯誤,同時顯示用戶通過View屬性指定的view(通過Master使用layout),下面的例子展示了如何使用HandleErrorAttribute filter

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

public ActionResult Index() {

...

上述例子,我們對NullReferenceException類型感興趣,希望出現異常時顯示SpecialErrorView

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

當呈現一個view時,HandleErrorAttribute filter傳遞一個HandleErrorInfo view model對象,你可以在消息中包含異常的細節,展示給用戶。如下例子,當現實錯誤信息時,使用View Model對象:

@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)-過濾器

使用Action和Result Filter

Action和Result Filter是常用的filter,可以用于任何目的。它們都遵循一個公共模式。內建的類創建filter,IActionFilter的類型,實現全部的接口。接口如下:

namespace System.Web.Mvc {

public interface IActionFilter {

void OnActionExecuting(ActionExecutingContext filterContext);

void OnActionExecuted(ActionExecutedContext filterContext);

    }

}

此接口定義了2個方法,MVC Framework 在action方法調用之前,先調用OnActionExecutin方法。在action方法調用之后,調用OnActionExecuted方法。

實現OnActionExecuting方法

The OnActionExecuting 方法在action方法在action方法調用之前先調用。你可以通過這個來檢查請求,選擇取消請求,修改請求,或者啟動另一個活動跨越action的調用。此方法的參數是一個ActionExecutingContext ,是ControllerContext的子類,有2個同樣的屬性,和你在其他context對象中看到的一樣。詳細描述如下表:

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

你可以有選擇的通過設置parameter的result屬性來取消請求,如下演示代碼:

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方法檢查請求是否是SSL的,如果不是,返回404-Not Found響應給用戶。

注意,如上例所示,你不需要將IActionFilter接口中的方法都實現,如果你不需要加任何邏輯,就置空。消息不要拋出NotImplementedException異常,因為如果你這樣做,exception filter就會被執行。

實現OnActionExecuted方法

你也可以使用filter去執行一些任務,跨越執行action方法。下面是一個簡單的例子計算action方法執行的時間開銷。

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方法,啟動一個計數器。當action方法完成后,OnActionExecuted方法調用。然后我們停止計時器,寫出響應,輸出所花的時間。結果圖如下:

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

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

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

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

實現Result Filter

Action filters和result filters有一些共同點. Result filters對于action results 就好比action filters

對于action methods. Result filters 實現IResultFilter 接口, 接口代碼如下:

namespace System.Web.Mvc {

public interface IResultFilter {

void OnResultExecuting(ResultExecutingContext filterContext);

void OnResultExecuted(ResultExecutedContext filterContext);

}

}

之前,我們說過action方法如何返回action result。這運行我們分離action的意圖和執行。當我們應用一個result filter到action方法上,一旦action方法返回action result,OnResultExecuting方法就被調用,但是在action result執行之前 。OnResultExecuted方法在action result執行后調用。這些方法的參數分別是ResultExecutingContext 和ResultExecutedContext 對象,它們和action filter的那部分非常相似。它們有相同的屬性,相同的效果。下例代碼展示了一個簡單的 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));

}

}

}

這個filter計算了執行result所需要的時間。把這個filter附加的action方法上。

...

[ProfileResult]

public ActionResult Index() {

return View();

}

...

現在我們轉到action方法,輸出的內容如下。

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

注意,從filter中獲得的性能信息出現在頁面底部。這是因為我們在 action result 執行后——也就是view已經呈現了,才寫下我們的消息。我們先前的filte在action result執行之前寫到response的,因此它出現在page的頂部。

使用內建的Action和Result Filter類

MVC Framework 包含了一個內建的類,可以創建action 和result filters.

但是不像內建的authorization 和exception filter, 它不提供任何有用的細節. 這個類是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) {

}

    }

}

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

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 類實現了IActionFilter 和IResultFilter 接口,意味著MVC Framework把這個繼承類看作兩種filter類型, 即使并不是所有的方法都被重寫。如果我們在上述的例子應用這個filter到action方法,我們的輸出就如下:

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

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

开鲁县| 新民市| 安康市| 炎陵县| 昭苏县| 洛川县| 龙山县| 宣化县| 崇信县| 绩溪县| 祥云县| 五台县| 杭州市| 高要市| 色达县| 阿克陶县| 蛟河市| 黔西县| 盘山县| 淮南市| 阿坝县| 沙雅县| 平罗县| 措勤县| 水富县| 桃源县| 晋中市| 石河子市| 丹寨县| 开化县| 鹤岗市| 新晃| 长沙市| 西乡县| 通河县| 华亭县| 蓬莱市| 六枝特区| 通辽市| 南丹县| 布尔津县|