Filter(篩選器)是基於AOP(面向方面編程)的設計,它的作用是Actionr的執行注入額外的邏輯,以達到橫切注入的目的。
IFilter
在WebAPI中所以的Filter都實現了IFilter接口 ,IFilter接口只有一個只讀屬性AllowMultiple,它表示同類的Filter是否可以應用到同一目標對象上。
public interface IFilter
{ 
bool AllowMultiple { get; } 
 }
 
        
FilterInfo
在HttpActionDescriptor與HttpControllerDescriptor中也存儲了Action使用到的Filter。但它不是直接以IFilter的形式進行存儲,也是以FilterInfo(System.Web.Http.Filters)。
public sealed class FilterInfo
 {
public FilterInfo(IFilter instance, FilterScope scope); 
public IFilter Instance { get; } 
public FilterScope Scope { get; } 
 }
 
        
在FilterInfo中有兩個屬性:Instance,Scope。其中Instance是IFilter對象。在實際對Filter運用中我們應該注意並發的情況,因為對於同一個Filter調用的都是同一個Filter對象。
FilterScope
對於FilterInfo類的Scope屬性,它表示Filter的域。在WebAPI中Filter有3個域:Global,Controller,Action。
public enum FilterScope
 { 
 Global = 0, 
 Controller = 10, 
 Action = 20, 
 }
 
        
對於Controller,Action的Filter添加都是采用特性(Attribute)的方式。對於全局Filter是添加在HttpConfiguration的Filter。
FilterProvider
WebAPI提供了IFilterProvider(System.Web.Http.Filters)用於提供不同域下的Filter。
public interface IFilterProvider
{
IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor); 
 }
 
        
在WebAPI中FilterProvider也是"標准化組件",但是它是以multi的形式注入的.WebAPI中IFilter有兩個默認實現: ConfigurationFilterProvider, ActionDescriptorFilterProvider,從命名上我們就可以知道前者是提供全局Filter,后者是提供Controller,Action的Filter。
5類Filter
WebAPI為我們定義了5類Filter。分別如下:
AuthenticationFilter:用於請求認證(IAuthenticationFilter)。
AuthorizationFilter:用於請求授權(IAuthorizationFilter)。
ActionFilter:ActionFilter:注冊的操作會在Action執行的前后被調用(IActionFilter)。
ExceptionFilter:當目標Action拋出異常是調用(IExceptionFilter)。
OverrideFilter:用於屏蔽當前域之前的Filter(IOverrideFilter)。
本文重點講后三類Filter,對於前兩類,后續再做跟進。對於后三類Filter默認實現是ActionFilterAttribute,ExceptionFilterAttribute,OverrideActionFilterAttribute。如下:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] 
public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IFilter
 {
protected ActionFilterAttribute(); 
public virtual void OnActionExecuted(HttpActionExecutedContext actionExecutedContext); 
public virtual Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken); 
public virtual void OnActionExecuting(HttpActionContext actionContext); 
public virtual Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken); 
 }
 
        
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] 
public abstract class ExceptionFilterAttribute : FilterAttribute, IExceptionFilter, IFilter
 { 
protected ExceptionFilterAttribute(); 
public virtual void OnException(HttpActionExecutedContext actionExecutedContext); 
public virtual Task OnExceptionAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken); 
 }
 
        
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] 
public sealed class OverrideActionFiltersAttribute : Attribute, IOverrideFilter, IFilter
 { 
public OverrideActionFiltersAttribute(); 
public Type FiltersToOverride { get; } 
 }
 
        
唯一性
因為Filter有三個域,那么在采用特性標示的方式注入Filter的,必定有可能會對同一個Action上注入多個相同的Filter。顯然在使用中一般不會允許這種情況發生。WebAPI中提供了相應的策略用來保證Filter的唯一性。即對FilterAttribute添加AttributeUsage特性,並將AllowMultiple設置為false.
當然這個設置過后你會發現在三個域上我還是可以添加相同的Filter,那么這個時候WebAPI會為我們篩選出一個Filter去調用。篩選規則如下:
Action>Controller>Global
即FilterScope的值越大,優先級超高。
ActionFilter
ActionFilterAttribute提供了4個虛方法: OnActionExecuted,OnActionExecutedAsync,OnActionExecuting,OnActionExecutingAsync 其實兩個異步方法只是對兩個同步的方法的封裝,所以我們一般只重寫兩個同步方法。
在執行順序上ActionFilter的規則是:
-  
          不同域:Global>ControllerAction
 -  
          相同域:按照注入順序執行
 
在執行OnActionExecuting的過程中如果給actionContext.Response賦值,那么Filter管道就會做返回處理,不再去做后續操作。
ExceptionFilter
在執行Action與整個ActionFilter管道中,如果拋出異常,
-  
          ExpceptionFilter的執行順序與ActionFilter正好相反
 -  
          ExceptionFilter管道處理的是整個ActionFilter管道拋出的異常,並不是單純的Action拋出的異常
 -  
          如果在ExceptionFilter管道中拋出異常,那么該ExceptionFilter都不會執行。
 
OverrideFilter
一個Action的所有Filter是Global,Controller,Action三個域下的Filter的總合,但有些時候我們並想要上一級域的Filter這個時候就需要用到OverrideFilter。WebAPI的OverrideActionFiltersAttribute只會屏蔽IActionFilter,並不會對其它的Filter進行屏蔽。
源碼
Github: https://github.com/BarlowDu/WebAPI (API_13)
