web api中具有多个过滤器的执行顺序

Hel*_*rld 46 c# asp.net action-filter asp.net-web-api asp.net-web-api2

我正在使用最新的web api.

我用一些不同的过滤器属性来注释一些控制器.

1 [Authorize]
2 [RessourceOwnerAttribute derived from AuthorizationFilterAttribute]
3 [InvalidModelStateAttribute derived from ActionFilterAttribute]
Run Code Online (Sandbox Code Playgroud)

我无法确定过滤器是按从上到下的顺序运行的.

如何定义执行顺序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

我还要为自己解决这个问题吗?

Kir*_*lla 70

有些事情需要注意:

  1. 过滤器按以下顺序执行操作:全局定义的过滤器 - >控制器特定的过滤器 - >特定于操作的过滤器.
  2. 授权过滤器 - >操作过滤器 - >异常过滤器
  3. 现在你似乎提到的问题与具有相同类型的多个过滤器有关(例如: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());
    
    Run Code Online (Sandbox Code Playgroud)
    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));
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
    //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; }
    }
    
    Run Code Online (Sandbox Code Playgroud)

  • 当我实现这个时,[Authorize]不起作用 (5认同)
  • 在哪个文件中添加`config.Services.Replace(...`Code? (3认同)
  • 再一次,config.Services.Replace(...代码在哪里? (2认同)

dkn*_*ack 17

我在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));
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,只会IOrderedFilter返回实现的过滤器.我有一个第三方属性被削减,因此没有执行.

所以我有两个可能的解决方案.

  1. 使用继承来创建第三方属性的扩展版本,以便实现它IOrderFilter.
  2. 更改方法以处理未实现的每个属性,IOrderFilterIOrderFilter订单号为0的IOrderFilter属性,并将其与属性组合,订购并返回它们.

第二种解决方案更好,因为它允许我IOrderFilter在未实现的第三方属性之前引入我的属性IOrderFilter.

样品

[NonOrderableThirdPartyAttribute]
[OrderableAttributeA(Order = -1)]
[OrderableAttributeB(Order = 1)]
[OrderableAttributeC(Order = 2)]
public async Task<IHttpActionResult> Post(... request) 
{
    // do something
}
Run Code Online (Sandbox Code Playgroud)

所以执行就是

  • 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);
    }
}
Run Code Online (Sandbox Code Playgroud)