前言
上一節我們詳細講解了過濾器的創建過程以及粗略的介紹了五種過濾器,用此五種過濾器對實現對執行Action方法各個時期的攔截非常重要。這一節我們簡單將講述在Action方法上、控制器上、全局上以及授權上的自定義特性的執行過程。
APiController
之前有講到該APiController,也就稍微介紹了,這節我們來詳細此Web API控制器的基類:
1 public abstract class ApiController : IHttpController, IDisposable 2 { 3 // Fields 4 private HttpConfiguration _configuration; 5 private HttpControllerContext _controllerContext; 6 private bool _disposed; 7 private ModelStateDictionary _modelState; 8 private HttpRequestMessage _request; 9 private UrlHelper _urlHelper; 10 11 // Methods 12 protected ApiController(); 13 public void Dispose(); 14 protected virtual void Dispose(bool disposing); 15 public virtual Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken); 16 protected virtual void Initialize(HttpControllerContext controllerContext); 17 internal static Func<Task<HttpResponseMessage>> InvokeActionWithActionFilters(HttpActionContext actionContext, CancellationToken cancellationToken, IEnumerable<IActionFilter> filters, Func<Task<HttpResponseMessage>> innerAction); 18 internal static Func<Task<HttpResponseMessage>> InvokeActionWithAuthorizationFilters(HttpActionContext actionContext, CancellationToken cancellationToken, IEnumerable<IAuthorizationFilter> filters, Func<Task<HttpResponseMessage>> innerAction); 19 internal static Task<HttpResponseMessage> InvokeActionWithExceptionFilters(Task<HttpResponseMessage> actionTask, HttpActionContext actionContext, CancellationToken cancellationToken, IEnumerable<IExceptionFilter> filters); 20 21 // Properties 22 public HttpConfiguration Configuration { get; set; } 23 public HttpControllerContext ControllerContext { get; set; } 24 public ModelStateDictionary ModelState { get; } 25 public HttpRequestMessage Request { get; set; } 26 public UrlHelper Url { get; set; } 27 public IPrincipal User { get; } 28 29 // Nested Types 30 private class FilterGrouping 31 { 32 // Fields 33 private List<IActionFilter> _actionFilters; 34 private List<IAuthorizationFilter> _authorizationFilters; 35 private List<IExceptionFilter> _exceptionFilters; 36 37 // Methods 38 public FilterGrouping(IEnumerable<FilterInfo> filters); 39 private static void Categorize<T>(IFilter filter, List<T> list) where T: class; 40 41 // Properties 42 public IEnumerable<IActionFilter> ActionFilters { get; } 43 public IEnumerable<IAuthorizationFilter> AuthorizationFilters { get; } 44 public IEnumerable<IExceptionFilter> ExceptionFilters { get; } 45 } 46 }
我們首先來看看此類中的一個私有類 FilterGrouping ,顧名思義是對過濾器分組,我們查看其構造函數看看:
public FilterGrouping(IEnumerable<FilterInfo> filters)
{
this._actionFilters = new List<IActionFilter>();
this._authorizationFilters = new List<IAuthorizationFilter>();
this._exceptionFilters = new List<IExceptionFilter>();
foreach (FilterInfo info in filters)
{
IFilter instance = info.Instance;
Categorize<IActionFilter>(instance, this._actionFilters);
Categorize<IAuthorizationFilter>(instance, this._authorizationFilters);
Categorize<IExceptionFilter>(instance, this._exceptionFilters);
}
}
我們僅僅只需 _actionFilters 為例,其余一樣,我們再來看看 Categorize 方法:
1 private static void Categorize<T>(IFilter filter, List<T> list) where T: class 2 { 3 T item = filter as T; 4 if (item != null) 5 { 6 list.Add(item); 7 } 8 }
從這里我們可以得知:
當我們在HttpActionDescriptor初始化創建了封裝了Filter對象的FilterInfo的集合列表,此時然后利用此類中的三個屬性類型:IActionFilter、IAuthorizationFilter、以及IExceptionFilter進行過濾器分組得到對應過濾器集合列表
執行過程原理解析
下面我們通過例子來看看之執行過程,我們自定義以下五個過濾器
/// <summary>
/// 全局的行為過濾器
/// </summary>
public class CustomConfigurationActionFilterAttribute : FilterAttribute, IActionFilter
{
public Task<HttpResponseMessage> ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
Console.WriteLine(this.GetType().Name);
return continuation();
}
}
/// <summary>
/// 控制器級行為過濾器
/// </summary>
public class CustomControllerActionFilterAttribute : FilterAttribute, IActionFilter
{
public Task<HttpResponseMessage> ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
Console.WriteLine(this.GetType().Name);
return continuation();
}
}
/// <summary>
/// 控制器方法級行為過濾器
/// </summary>
public class CustomActionFilterAttribute : FilterAttribute, IActionFilter
{
public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
Console.WriteLine(this.GetType().Name);
return continuation();
}
}
/// <summary>
/// 控制器級授權訪問過濾器
/// </summary>
public class CustomControllerAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter
{
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
Console.WriteLine(this.GetType().Name);
return continuation();
}
}
/// <summary>
/// 控制器方法級授權訪問過濾器
/// </summary>
public class CustomControllerActionAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter
{
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
Console.WriteLine(this.GetType().Name);
return continuation();
}
}
接下來就是實現過濾器,配置文件中配置全局過濾器
config.Filters.Add(new CustomConfigurationActionFilterAttribute());
控制器及方法上過濾器
[CustomControllerAuthorizationFilter]
[CustomControllerActionFilter]
public class ProductController : ApiController
{
[CustomActionFilter]
[CustomControllerActionAuthorizationFilter]
public string GetFilter()
{
var sb = new StringBuilder();
var actionSelector = this.Configuration.Services.GetActionSelector();
var actionDesciptor = actionSelector.SelectAction(this.ControllerContext);
foreach (var filterInfo in actionDesciptor.GetFilterPipeline())
{
sb.AppendLine("【FilterName:" + filterInfo.Instance.GetType().Name + ",FilterScope:" + filterInfo.Scope.ToString() + "】");
}
return sb.ToString();
}
}
最后來查看其結果:
看到這里是不是有點疑惑怎么按照Global->Controller->Action來進行排序,如果你看過前面文章就會知道這是過濾器管道按照FilterScope來生成的,實際上在服務器端生成的順序為 CustomControllerAuthorizationFilterAttribute 、 CustomControllerActionAuthorizationFilterAttribute 、 CustomConfigurationActionFilterAttribute 、 CustomControllerActionFilterAttribute 以及 CustomActionFilterAttribute 由此我們得出結論:
授權過濾器不管任何的FilterScope都是優於行為過濾器,而在同一種類型的過濾器中是根據FilterScope來確定執行順序的。
總結
有關更多深入的內容就不再探討,本想多寫一點,但是狀態不佳加上更多內容比較復雜以免說不太明白雲里霧里,想想還是算了,就這樣了,下面還是給出其一張執行的詳細示意圖,來源【過濾器執行過程】
