Ред на изпълнение с множество филтри в уеб API

Използвам най-новия 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

Все още ли трябва да поправя това за себе си??


person HelloWorld    schedule 07.02.2014    source източник
comment
Има ли тази връзка: strathweb.com/2012/06/ помощ?   -  person Devesh    schedule 10.04.2018


Отговори (3)


Някои неща, които трябва да отбележите тук:

  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());
    

    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; }
    }
    
person Kiran Challa    schedule 07.02.2014
comment
Кой файл да добавите кода config.Services.Replace(...? - person Jeff Tian; 06.10.2014
comment
@KiranChalla Какво ще кажете за глобално дефинирани филтри за действие? - person lbrahim; 05.11.2014
comment
Изпълнява глобално дефинирания филтър, независимо каква колекция е подредена. Все пак около това? - person lbrahim; 05.11.2014
comment
И отново, къде отива кодът config.Services.Replace(...? - person freakinthesun; 21.08.2015
comment
@freakinthesun: Обаждането до config.Services.Replace отива във вашия Startup, ако хоствате с тръбопровода OWIN, или в Global.asax.cs, ако не сте. - person Tomas Aschan; 07.12.2015
comment
Имах друг отговор, предоставящ някои подобрения. Чувствайте се свободни да погледнете. - person dknaack; 01.03.2016
comment
@MIKE Имам същия проблем - причинен е от обаждането до config.Services.Replace, но в момента нямам решение. - person Dai; 03.09.2016
comment
За справка, ред на филтрите на: tutorialspoint.com/asp.net_mvc/asp. net_mvc_filters.htm - person Abacus; 05.04.2019

Имах някои проблеми с решението от отговора на 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, ще бъдат върнати. Имах атрибут на трета страна, който се отрязва и в резултат на това не се изпълнява.

Така че имах две възможни решения.

  1. Използвайте наследяване, за да създадете разширена версия на атрибута на трета страна, за да го накарате да прилага и IOrderFilter.
  2. Променете метода, за да третирате всеки атрибут, който не прилага IOrderFilter като атрибут IOrderFilter с пореден номер 0 и го комбинирайте с атрибутите 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);
    }
}
person dknaack    schedule 01.03.2016

Ако имате няколко филтъра от един и същи вид, редът на изпълнение ще бъде Глобален -> Контролер -> Действие

А за филтър за оторизация, ако зададете няколко филтъра на различни нива, те ще бъдат комбинирани с „И“ и ще бъдат изчислени в горния ред на изпълнение.

И процесът на оторизация ще се провали при първия неуспешен филтър.

За повече подробности можете да проверите тази публикация.

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.1

person Shawn Teng    schedule 12.09.2018