I had some problems with the solution from Kiran Challa 's answer.
Here is my modification.
The problem was in the method
private IEnumerable<FilterInfo> OrderFilters(IEnumerable<IFilter> filters, FilterScope scope)
{
return filters.OfType<IOrderedFilter>()
.OrderBy(filter => filter.Order)
.Select(instance => new FilterInfo(instance, scope));
}
As you can see only filters that implement IOrderedFilter
will get returned. I had a third party attribute that gets cut of and as a result not executed.
So i had two possible solutions.
- Use inheritance to create a extended version of the third party attribute in order to make it implement
IOrderFilter
too.
- Change the method to treat every attribute wich does not implement
IOrderFilter
like a IOrderFilter
attribute with the order number of 0 and combine it with the IOrderFilter
attributes, order and return them.
The second solution is better cause it allows me to bring my IOrderFilter
attribute before third party attributes that does not implement IOrderFilter
.
Sample
[NonOrderableThirdPartyAttribute]
[OrderableAttributeA(Order = -1)]
[OrderableAttributeB(Order = 1)]
[OrderableAttributeC(Order = 2)]
public async Task<IHttpActionResult> Post(... request)
{
// do something
}
So the execution would be
- OrderableAttributeA
- NonOrderableThirdPartyAttribute
- OrderableAttributeB
- OrderableAttributeC
So here is the modified 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);
}
}