Kolejność wykonania z wieloma filtrami w web api
Używam najnowszego web api
.
Dodaję niektóre kontrolery z 3 różnymi atrybutami filtrów.
1 [Authorize]
2 [RessourceOwnerAttribute derived from AuthorizationFilterAttribute]
3 [InvalidModelStateAttribute derived from ActionFilterAttribute]
Nie mogę być pewien, czy filtry działają w kolejności, w jakiej są deklarowane od góry do dołu.
Jak określić kolejność wykonania w web api 2.1
?
3 answers
Kilka rzeczy do odnotowania tutaj:
- filtry są wykonywane w następującej kolejności dla akcji: globalnie Definiowane Filtry - > Filtry specyficzne dla kontrolera- > filtry specyficzne dla akcji.
- Filtry Autoryzacyjne - > Filtry Akcji - > Wyjątek Filtry
-
Teraz problem, o którym wspominasz, jest związany z posiadające wiele filtrów tego samego rodzaju (np.
ActionFilterAttribute
dekorowane na kontroler lub działanie. Jest to przypadek, który nie gwarancja porządek jako jego opiera się na refleksji.). W tym przypadku istnieje sposób aby to zrobić w Web API przy użyciu niestandardowej implementacjiSystem.Web.Http.Filters.IFilterProvider
. Próbowałem następujących i zrobił kilka testów, aby to zweryfikować. Wygląda na to, że działa dobrze. Możesz spróbować i sprawdzić, czy działa zgodnie z oczekiwaniami.// 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; } }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-13 12:35:24
Miałem pewne problemy z rozwiązaniem z odpowiedzi Kiran Challa. Oto moja modyfikacja.
Problem tkwił w metodzie
private IEnumerable<FilterInfo> OrderFilters(IEnumerable<IFilter> filters, FilterScope scope)
{
return filters.OfType<IOrderedFilter>()
.OrderBy(filter => filter.Order)
.Select(instance => new FilterInfo(instance, scope));
}
Jak widać zwracane będą tylko filtry implementujące IOrderedFilter
. Miałem atrybut strony trzeciej, który zostaje wycięty i w rezultacie nie jest wykonywany.
Więc miałem dwa możliwe rozwiązania.
- użyj dziedziczenia, aby utworzyć rozszerzoną wersję atrybutu third party, aby zaimplementować
IOrderFilter
też. - Zmień metodę traktowania każdego atrybutu, który nie implementuje
IOrderFilter
Jak atrybutIOrderFilter
o numerze porządkowym 0 i połącz go z atrybutamiIOrderFilter
, Uporządkuj i zwróć je.
Drugie rozwiązanie jest lepsze, ponieważ pozwala mi przenieść mój atrybut IOrderFilter
przed atrybuty stron trzecich, które nie implementują IOrderFilter
.
Próbka
[NonOrderableThirdPartyAttribute]
[OrderableAttributeA(Order = -1)]
[OrderableAttributeB(Order = 1)]
[OrderableAttributeC(Order = 2)]
public async Task<IHttpActionResult> Post(... request)
{
// do something
}
Więc egzekucja byłaby
- OrderableAttributeA
- NonOrderableThirdPartyAttribute
- OrderableAttributeB
- OrderableAttributeC
Oto zmodyfikowany kod
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);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-01 09:36:35
Jeśli masz kilka filtrów tego samego rodzaju, kolejność wykonania będzie Global -> Controller - > Action
I dla filtra autoryzacji, jeśli ustawisz wiele filtrów na różnych poziomach, zostaną one połączone z "I" i zostaną obliczone w powyższej kolejności wykonania.
I proces autoryzacji zakończy się niepowodzeniem przy pierwszym nieudanym filtrze.
Aby uzyskać więcej informacji, możesz sprawdzić to poczta.
Https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.1
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-12 08:54:32