代碼詳解Asp.Net MVC過濾器

來源:互聯網
上載者:User
本篇文章主要介紹了Asp.Net MVC學習總結之過濾器詳解,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

一、過濾器簡介

1.1、理解什麼是過濾器

1、過濾器(Filters)就是向請求處理管道中注入額外的邏輯。提供了一個簡單而優雅的方式來實現橫切關注點。

2、所謂的過濾器(Filters),MVC架構裡面的過濾器完全不同於ASP.NET平台裡面的Request.Filters和Response.Filter對象,它們主要是實現請求和響應流的傳輸。通常我們所說的過濾器是指MVC架構裡面的過濾器。

3、過濾器可以注入一些代碼邏輯到請求處理管道中,是基於C#的Attribute的實現。當負責調用Action的類ControllerActionInvoker在調用執行Action的時候會檢查Action上面的Attribute並查看這些Attribute是否實現了指定的介面,以便進行額外的代碼注入處理

1.2、理解為什麼要使用過濾器

假設你做了一個小項目,其中某個功能是操作系統管理使用者資訊模組,有這樣一個需求,對使用者資訊管理必須是已通過認證的使用者才能操作,我們可以在每一個Action方法裡面檢查認證請求,如下所示:

using MvcFilterDmo.Core;using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using System.Web.Security;namespace MvcFilterDmo.Controllers{  public class HomeController : Controller  {    public ActionResult Index()    {      if (!Request.IsAuthenticated)      {        FormsAuthentication.RedirectToLoginPage();      }      //操作部分...      return View();    }    public ActionResult Insert()    {      if (!Request.IsAuthenticated)      {        FormsAuthentication.RedirectToLoginPage();      }      //操作部分...      return View();    }    public ActionResult Update()    {      if (!Request.IsAuthenticated)      {        FormsAuthentication.RedirectToLoginPage();      }      //操作部分...      return View();    }    public ActionResult Delete()    {      if (!Request.IsAuthenticated)      {        FormsAuthentication.RedirectToLoginPage();      }      //操作部分...      return View();    }    //其他Action操作方法    //...  }}

通過上面的代碼,可以發現使用這種方式檢查請求認證有許多重複的地方,這也就是為什麼要使用過濾器的原因,使用過濾器可以實現相同的效果。如下所示:

using MvcFilterDmo.Core;using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using System.Web.Security;namespace MvcFilterDmo.Controllers{  [Authorize]  public class HomeController : Controller  {    public ActionResult Index()    {      //操作部分...      return View();    }    public ActionResult Insert()    {      //操作部分...      return View();    }    public ActionResult Edit()    {       //操作部分...      return View();    }    public ActionResult Delete()    {      //操作部分...      return View();    }    //其他Action操作方法    //...  }}

過濾器是.NET裡面的特性(Attributes),它提供了添加到請求處理管道的額外方法。這裡使用Authorize過濾器可以實現同樣的效果,不過代碼就顯然比之前更加簡潔優雅。

二、過濾器的使用

2.1、基本類型的過濾器

過濾器實現的機制:在MVC架構調用一個Action之前,它會檢查方法的定義中是否實現了特性(Attributes),如果實現的話,那麼在請求處理管道適當的位置,該特性定義的方法會被調用。

ActionFilterAttribute類既實現了IactionFilter介面,也實現IResultFilter介面。這是一個抽象類別,它要求你必須提供一個實現。AuthorizeAttribute和HandleErrorAttribute類,則包含了一些有用的特性,並且可以不必建立衍生類別進行使用。

2.2、過濾器的應用、應用方式以及執行順序

應用: 過濾器可以被應用到控制器上也可以用到Action方法上,應用到控制上時,表示所有的Action方法都有了這個過濾器,並且可以混合使用,或多次使用,如下所示:

[A] //表示所有的Action方法都會應用A過濾器Public class DemoController:Controller{  [B]//B,C過濾器只作用於此Action方法,但它也會有A過濾器的應用效果  [C]  Public ActionResult Index()  {     //操作部分...     return View();  } }

應用方式:特性的方式,如上面代碼所示。

執行順序:相同類型過濾器,執行順序靠近方法的先執行,不同類型的過濾器一般執行順序為【authorize--->action--->actionResult】至於異常過濾器不分先後,只要拋出異常時就會執行異常過濾器。如果要調整執行順序,可以通過調整Order方法值大小來控制執行順序,值越小,越先執行。是Action/Result過濾器應用的執行順序圖

(1)、相同類型過濾器應用樣本:兩個自訂Action過濾器MyFirstFilter,MyThreeFilter應用到同一個Action方法Index上。

Three控制器代碼如下:

MyFirstFilter 代碼如下:

MyThreeFilter代碼如下:

運行結果如下:

(2)、不同類型過濾器應用樣本:有一個自訂Action過濾器MyFirstFilter,有一個自訂Result過濾器MySecondFilter,應用到同一個Action方法Index上。

Three控制器代碼如下:

MyFirstFilter 代碼如下:

MySecondFilter代碼如下:

運行結果如下:

看完上面的解釋,可能你現在對這些過濾器的執行順序,以及如何自訂過濾器還不明白,不要緊,下面我們會逐一介紹這幾個基本的過濾器的使用,以及如何自訂過濾器。

2.3、使用授權過濾器

所有實現了IAuthorizationFilter介面的都可以稱之為授權過濾器:其定義如下:

 public interface IAuthorizationFilter    {       void OnAuthorization(AuthorizationContext filterContext);    }

由於MVC架構系統內建的AuthorizeAttribute實現有一些突出的功能,而這種牽涉到安全的代碼一定要謹慎的編寫,所以一般我們不會直接實現這個介面,而是去繼承AuthorizeAttribute這個類,並重寫其AuthorizeCore方法,簽名為: bool AuthorizeCore(HttpContextBase httpContext) 而處理授權失敗的時候,可以重寫其HandleUnauthorizedRequest方法,其簽名為: void HandleUnauthorizedRequest(AuthorizationContext context) 。注意:驗證與授權是兩回事,驗證發生在授權之前。

預設的授權過濾器已經有了驗證的功能,其驗證的機理是利用Asp.net平台內建的驗證機制,如表單驗證和Windows驗證。除了驗證功能,它本身還有授權的功能。授權過濾器是所有過濾器中最早啟動並執行。

經過Route到達了控制器的時候,在調用Action之前,MVC架構會檢測在相關的Action上是否有授權過濾器,如果有會調用OnAuthorization方法,如果此方法批准了請求,才會調用相應的Action。

使用授權過濾器幾種情況如下:

1.直接在Action上或者控制器上加Authorize,表示啟用了驗證,但不牽涉到授權。

2.添加Authorize(Users=“a,b”)],表示啟用了驗證,並且也啟用了授權,只有a或者b使用者能訪問此控制器。

3.當添加Authorize(Roles=“admin,Member”)]時的步驟如下:

---利用asp.net內建的角色提供者,或者實現自己的角色提供者,實現自己的角色提供者時,只需要整合RoleProvider類型,並實現其中的所有方法或部分方法,最好實現所有方法。

---在Web程式的根目錄的Web.config檔案中配置角色管理者。

---在適當的Action中利用Roles類型來訪問自己建立的RoleProvider中的相關方法。

使用內建的授權過濾器

MVC架構內建的授權過濾器AuthorizeAttribute,它允許我們使用這個類的兩個公用屬性來指定授權策略,如下所示:

Users和Roles兩者是並且的關係,例如Users=“a,b,c”,Roles=“admin”,表示使用者是a,b,c 其中一個並且是Admin角色才能訪問。

建立自訂的授權過濾器

方式一:直接實現IAuthorizationFilter介面,但不推薦這樣做,因為牽涉到安全方面的代碼。

方式二:繼承AuthorizeAttribute這個類,並重寫其AuthorizeCore方法,簽名為: bool AuthorizeCore(HttpContextBase httpContext),代碼如下所示:

public class MyAuthorizeAttribute : AuthorizeAttribute  {    private string[] allowedUsers;    public MyAuthorizeAttribute(params string[] users)    {      allowedUsers = new string[] { "admin", "user1", "xf" };    }    protected override bool AuthorizeCore(HttpContextBase httpContext)    {      return httpContext.Request.IsAuthenticated &&allowedUsers.Contains(httpContext.User.Identity.Name,         StringComparer.InvariantCultureIgnoreCase);    }  }

2.4、使用動作過濾器

動作過濾器是可以以用於任何目的的多用途過濾器,建立自訂動作過濾器需要實現IActionFilter介面,該介面代碼如下所示:

該介面定義了兩個方法,MVC架構在調用動作方法之前,會調用OnActionExecting方法。在調用動作方法之後,則會調用OnActionExecuted方法。

實現OnActionExecting方法

參數ActionExecutingContext對象繼承於ControllerContext,其中的2個屬性:

ActionDescriptor:提供了關於Action方法的相關資訊

Result:類型為ActionResult,通過給這個屬性設定一個非null的值就可以取消這個請求。

我們可以用過濾器來取消一個請求,通過設定Result屬性即可。代碼如下所示:

public class MyActionFilterAttribute : FilterAttribute, IActionFilter  {    public void OnActionExecuting(ActionExecutingContext filterContext)    {      if(filterContext.HttpContext.Request.IsLocal)      {        filterContext.Result = new HttpNotFoundResult();      }    }    public void OnActionExecuted(ActionExecutedContext filterContext)    {      //未做實現    }  }

這個例子通過用OnActionExecuting方法檢查請求是否來自本地機器,如果是,編隊使用者返回一個“404”未找到的響應。運行結果如:

實現OnActionExecuted方法

我們也可以通過OnActionExecuted方法來執行一些跨越動作方法的任務,下面這個例子是計算動作方法啟動並執行時間,代碼如下:

public class MyActionFilterAttribute : 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("動作方法延遲的時間: {0}",            timer.Elapsed.TotalSeconds));      }    }  }}

我們將自訂的動作過濾器MyActionFilter應用到HomeController的Index方法上,運行結果如下:

2.5、使用結果過濾器

結果過濾器是多用途的過濾器,他會對動作方法所產生結果進行操作,結果過濾器實現IResultFilter介面,建立自訂結果過濾器需要現IResultFilter介面,該介面代碼如下所示:

當結果過濾器運用於一個動作方法時,會在動作方法返回動作結果之前,調用OnResultExecuting方法,在返回動作結果之後,會調用OnResultExecuted方法。下面這個例子是計算動作方法返回結果啟動並執行時間,代碼如下:

public class MyResultFilterAttribute : 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("結果執行延遲時間: {0}", timer.Elapsed.TotalSeconds));    }}

我們將自訂的結果過濾器MyResultFilter應用到HomeController的Index方法上,運行結果如下:

需要注意的是:動作過濾器是運行在頁面輸出之前,結果過濾器是運行在頁面輸出之後。

2.6、使用異常過濾器

異常過濾器只有在調用一個動作方法而拋出未處理的異常才會運行,這種異常來自以下位置:

A、另一種過濾器(授權、動作、或結果過濾器)。

B、動作方法本身。

C、當動作結果被執行時。

使用內建的異常過濾器

HandleErrorAttribute(處理常式錯誤特性),它是MVC內嵌的異常過濾器,有以下3個重要的屬性:

1.ExceptionType:類型為Type,表示希望被此過濾器處理的異常類型,包括其子類型,預設值為System.Exception

2.View:類型為string,表示此過濾器呈遞的視圖頁面,預設值為Error

3.Master:呈遞的視圖頁的母板頁,如果不指定,視圖會用其預設的主版頁面

內嵌的HandleErrorException只有在設定檔Web.config中配置的CustomError 的mode設定為on的時候才生效(其預設模式為RemoteOnly),如所示:

此過濾器還會給視圖傳遞一個HandleErrorInfo類型的對象給視圖,以便視圖可以顯示一些額外的關於錯誤的資訊。下面是使用異常過濾器的樣本。

應用到Index動作方法上:

在Views/Shared檔案夾下添加一個顯示異常資訊的視圖頁SpecialError.cshtml,頁面代碼如下:

@model HandleErrorInfo  <!DOCTYPE html>  <html>  <head>    <meta name="viewport" content="width=device-width" />    <title>SpecialError</title>  </head>  <body>    <p>      <p>        There was a<b>@Model.Exception.GetType().Name</b>        while rendering<b>@Model.ControllerName</b>'s        <b>@Model.ActionName</b> action      </p>    </p>  </body></html>

運行結果如下:

建立自訂的異常過濾器

如果我們對異常過濾器有特殊的需求,可以通過自訂的異常過濾器來完成,建立自訂異常過濾器必須實現IExceptionFilter介面,該介面代碼如下:

當一個未知處理異常發生時,OnException方法會被調用。該方法的傳遞一個ExceptionContext對象,派生於ControllerContext類,定義了一些額外的過濾器專有屬性如下表所示:

拋出的異常通過Exception屬性是可以訪問的。通過把ExceptionHandled屬性設定為true,一個異常過濾器可以報告它已經處理了該異常,應用於一個動作的所有異常過濾器都會被調用。

需要注意的是:如果一個動作方法的所有異常過濾器均為把ExceptionHandled屬性設定為true,MVC架構將使用預設的ASP.NET例外處理常式。

Result屬性有異常過濾器使用,以告訴MVC架構要做什麼,異常過濾器的兩個主要應用是記錄該異常到日誌,並把適當的訊息顯示給使用者。下面的代碼將示範通過建立一個自訂的異常過濾器,當一個特定的鐘類的未處理異常出現時,把該使用者重新導向到一個指定的錯誤頁面。

public class MyExectionAttribute:FilterAttribute,IExceptionFilter  {    public void OnException(ExceptionContext filterContext)    {      if(!filterContext.ExceptionHandled&&        filterContext.Exception is NullReferenceException)      {        filterContext.Result = new RedirectResult("~/Content/SpecialErrorPage.html");        filterContext.ExceptionHandled = true;      }    }}

然後在項目根目錄添加一個名為Content的檔案夾,在該檔案夾下建立SpeciErrorPage.html檔案,當異常被處理時,將以這個錯誤頁面顯示個使用者。該頁面代碼如下:

<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>  <title></title></head><body>  <h1>Sorry</h1>  <p>this is a Excetption test</p>  There was aNullReferenceException while renderingHome's Index action </body></html>

在控制器中應用MyExection異常過濾器,並主動讓其拋出一個Null 參考異常,以便測試。

public class HomeController : Controller  {    [MyExection]    public ActionResult Index()    {      throw new NullReferenceException();    }  }

運行結果如下:

總結:本文章簡單總結了對過濾器的理解以及如何使用MVC架構內建基本的過濾器和如何自訂過濾器及應用。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.