我正在使用最新的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#
我还需要为自己解决这个问题吗?
答案 0 :(得分:66)
有些事情需要注意:
现在你提到的问题与你有关
拥有相同类型的多个过滤器(例如:多个)
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; }
}
答案 1 :(得分:15)
我在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
}
所以执行将是
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);
}
}
答案 2 :(得分:1)
如果您有多个相同类型的过滤器,则执行顺序为 全局->控制器->操作
对于授权过滤器,如果您将多个过滤器设置为不同级别,则它们将与“ AND”组合,并按上述执行顺序进行计算。
并且授权过程将在第一个失败的过滤器上失败。
有关更多详细信息,您可以查看此帖子。
https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.1