Web api中多个过滤器的执行顺序
Posted
技术标签:
【中文标题】Web api中多个过滤器的执行顺序【英文标题】:Order of execution with multiple filters in web api 【发布时间】:2014-03-04 21:46:30 【问题描述】:我正在使用最新的web api
。
我确实用 3 个不同的过滤器属性注释 一些 控制器。
1 [Authorize]
2 [RessourceOwnerAttribute derived from AuthorizationFilterAttribute]
3 [InvalidModelStateAttribute derived from ActionFilterAttribute]
我不能确定过滤器是否按照它们声明的顺序从上到下运行。
web api 2.1
中如何定义执行顺序?
https://aspnetwebstack.codeplex.com/workitem/1065#
http://aspnet.uservoice.com/forums/147201-asp-net-web-api/suggestions/3346720-execution-order-of-mvc4-webapi-action-filters
我还需要自己解决这个问题吗??
【问题讨论】:
这个链接:strathweb.com/2012/06/…有帮助吗? 【参考方案1】:这里有几点需要注意:
-
过滤器按以下顺序执行操作:全局
定义的过滤器 -> 特定于控制器的过滤器 -> 特定于操作的过滤器。
授权过滤器 -> 操作过滤器 -> 异常
过滤器
现在您似乎提到的问题与
具有多个相同类型的过滤器(例如:多个
ActionFilterAttribute
装饰在一个
控制器或动作。这种情况不能保证
顺序是基于反射的。)。对于这种情况,有一种方法
使用自定义实现在 Web API 中执行此操作
System.Web.Http.Filters.IFilterProvider
。我试过以下
并做了一些测试来验证它。它似乎工作正常。
您可以试一试,看看它是否按您的预期工作。
// Start clean by replacing with filter provider for global configuration.
// For these globally added filters we need not do any ordering as filters are
// executed in the order they are added to the filter collection
config.Services.Replace(typeof(IFilterProvider), new System.Web.Http.Filters.ConfigurationFilterProvider());
// Custom action filter provider which does ordering
config.Services.Add(typeof(IFilterProvider), new OrderedFilterProvider());
public class OrderedFilterProvider : IFilterProvider
public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
// controller-specific
IEnumerable<FilterInfo> controllerSpecificFilters = OrderFilters(actionDescriptor.ControllerDescriptor.GetFilters(), FilterScope.Controller);
// action-specific
IEnumerable<FilterInfo> actionSpecificFilters = OrderFilters(actionDescriptor.GetFilters(), FilterScope.Action);
return controllerSpecificFilters.Concat(actionSpecificFilters);
private IEnumerable<FilterInfo> OrderFilters(IEnumerable<IFilter> filters, FilterScope scope)
return filters.OfType<IOrderedFilter>()
.OrderBy(filter => filter.Order)
.Select(instance => new FilterInfo(instance, scope));
//NOTE: Here I am creating base attributes which you would need to inherit from.
public interface IOrderedFilter : IFilter
int Order get; set;
public class ActionFilterWithOrderAttribute : ActionFilterAttribute, IOrderedFilter
public int Order get; set;
public class AuthorizationFilterWithOrderAttribute : AuthorizationFilterAttribute, IOrderedFilter
public int Order get; set;
public class ExceptionFilterWithOrderAttribute : ExceptionFilterAttribute, IOrderedFilter
public int Order get; set;
【讨论】:
在哪个文件中添加config.Services.Replace(...
代码?
@KiranChalla 全局定义的操作过滤器怎么样?
无论集合是什么顺序,它都会执行全局定义的过滤器。无论如何围绕这个?
再一次,config.Services.Replace(... 代码去哪儿了?
我有另一个答案提供了一些改进。随意看看。【参考方案2】:
我对 Kiran Challa 的回答中的解决方案有一些疑问。 这是我的修改。
问题出在方法上
private IEnumerable<FilterInfo> OrderFilters(IEnumerable<IFilter> filters, FilterScope scope)
return filters.OfType<IOrderedFilter>()
.OrderBy(filter => filter.Order)
.Select(instance => new FilterInfo(instance, scope));
如您所见,只有实现IOrderedFilter
的过滤器会被返回。我有一个第三方属性被删除,因此没有执行。
所以我有两种可能的解决方案。
-
使用继承创建第三方属性的扩展版本,以使其也实现
IOrderFilter
。
更改方法以处理每个未实现IOrderFilter
的属性,就像订单号为0 的IOrderFilter
属性,并将其与IOrderFilter
属性结合,排序并返回它们。
第二种解决方案更好,因为它允许我将IOrderFilter
属性放在未实现IOrderFilter
的第三方属性之前。
示例
[NonOrderableThirdPartyAttribute]
[OrderableAttributeA(Order = -1)]
[OrderableAttributeB(Order = 1)]
[OrderableAttributeC(Order = 2)]
public async Task<IHttpActionResult> Post(... request)
// do something
所以执行将是
OrderableAttributeA NonOrderableThirdPartyAttribute OrderableAttributeB OrderableAttributeC所以这里是修改后的代码
public class OrderedFilterProvider : IFilterProvider
public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
// controller-specific
var controllerSpecificFilters = OrderFilters(actionDescriptor.ControllerDescriptor.GetFilters(), FilterScope.Controller);
// action-specific
var actionSpecificFilters = OrderFilters(actionDescriptor.GetFilters(), FilterScope.Action);
return controllerSpecificFilters.Concat(actionSpecificFilters);
private IEnumerable<FilterInfo> OrderFilters(IEnumerable<IFilter> filters, FilterScope scope)
// get all filter that dont implement IOrderedFilter and give them order number of 0
var notOrderableFilter = filters.Where(f => !(f is IOrderedFilter))
.Select(instance => new KeyValuePair<int, FilterInfo>(0, new FilterInfo(instance, scope)));
// get all filter that implement IOrderFilter and give them order number from the instance
var orderableFilter = filters.OfType<IOrderedFilter>().OrderBy(filter => filter.Order)
.Select(instance => new KeyValuePair<int, FilterInfo>(instance.Order, new FilterInfo(instance, scope)));
// concat lists => order => return
return notOrderableFilter.Concat(orderableFilter).OrderBy(x => x.Key).Select(y => y.Value);
【讨论】:
【参考方案3】:如果您有多个相同类型的过滤器,执行顺序将是 全局 -> 控制器 -> 动作
而对于授权过滤器,如果你设置了多个不同级别的过滤器,它们将与一个“AND”结合起来,并按照上述执行顺序进行计算。
并且授权过程将在第一个失败的过滤器处失败。
更多详情,您可以查看这篇文章。
https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.1
【讨论】:
以上是关于Web api中多个过滤器的执行顺序的主要内容,如果未能解决你的问题,请参考以下文章