it-swarm.com.de

Ausführungsreihenfolge mit mehreren Filtern in Web-API

Ich verwende den neuesten web api.

Ich kommentiere einige Controller mit 3 verschiedenen Filterattributen.

1 [Authorize]
2 [RessourceOwnerAttribute derived from AuthorizationFilterAttribute]
3 [InvalidModelStateAttribute derived from ActionFilterAttribute]

Ich kann nicht sicher sein, dass die Filter in der Reihenfolge laufen, in der sie von oben nach unten deklariert werden.

Wie definiere ich die Reihenfolge der Ausführung in 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-filter

Muss ich das immer noch reparieren?

38
HelloWorld

Einige Dinge hier zu beachten: 

  1. Filter werden in der folgenden Reihenfolge für eine Aktion ausgeführt: Global Definierte Filter -> Controllerspezifische Filter -> Aktionsspezifische Filter. 
  2. Berechtigungsfilter -> Aktionsfilter -> Ausnahme Filter 
  3. Das Problem, das Sie anscheinend zu erwähnen scheinen, hängt damit zusammen, dass mehrere Filter der gleichen Art hat (z. B .: mehrere ActionFilterAttribute auf einem Controller oder einer Aktion. Dies ist der Fall, der dies tun würde keine Garantie .__ die Bestellung als auf Reflexion basiert.). Für diesen Fall gibt es eine Möglichkeit, In der Web-API mithilfe der benutzerdefinierten Implementierung von System.Web.Http.Filters.IFilterProvider auszuführen. Ich habe Folgendes ausprobiert und einige Tests durchgeführt, um es zu überprüfen. Es scheint gut zu funktionieren. Sie können es ausprobieren und sehen, ob es wie erwartet funktioniert. 

    // 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; }
    }
    
63
Kiran Challa

Ich hatte einige Probleme mit der Lösung von Kiran Challas Antwort ... Hier ist meine Modifikation.

Das Problem lag in der Methode 

private IEnumerable<FilterInfo> OrderFilters(IEnumerable<IFilter> filters, FilterScope scope)
{
    return filters.OfType<IOrderedFilter>()
                    .OrderBy(filter => filter.Order)
                    .Select(instance => new FilterInfo(instance, scope));
}

Wie Sie sehen, werden only - Filter, die IOrderedFilter implementieren, zurückgegeben. Ich hatte ein Drittanbieterattribut, das abgeschnitten und als Ergebnis nicht ausgeführt wird.

Ich hatte also zwei mögliche Lösungen.

  1. Verwenden Sie die Vererbung, um eine erweiterte Version des Drittanbieterattributs zu erstellen, damit auch IOrderFilter implementiert wird.
  2. Ändern Sie die Methode, um jedes Attribut zu behandeln, das IOrderFilter nicht wie ein IOrderFilter-Attribut mit der Bestellnummer 0 implementiert, und kombinieren Sie es mit den Attributen IOrderFilter

Die zweite Lösung ist besser, weil es mir ermöglicht, mein IOrderFilter-Attribut vor den Attributen von Drittanbietern zu setzen, die IOrderFilter nicht implementieren.

Probe

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

So wäre die Hinrichtung 

  • OrderableAttributeA
  • NonOrderableThirdPartyAttribute
  • OrderableAttributeB
  • OrderableAttributeC

Hier ist also der modifizierte Code

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);
    }
}
14
dknaack

Wenn Sie über mehrere Filter derselben Art verfügen, lautet die Ausführungsreihenfolge Global -> Controller -> Action

Wenn Sie für den Berechtigungsfilter mehrere Filter auf verschiedenen Ebenen festlegen, werden diese mit einem "UND" kombiniert und in der obigen Ausführungsreihenfolge berechnet. 

Der Autorisierungsprozess schlägt beim ersten fehlgeschlagenen Filter fehl.

Für weitere Details können Sie diesen Beitrag überprüfen.

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

0
Shawn Teng