Move global filters addition to AD creation time
Add origin, and simplify sorting. Add type filter
This commit is contained in:
parent
9132d32fa4
commit
7ddf8a7bdb
|
|
@ -18,6 +18,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public List<ParameterDescriptor> Parameters { get; set; }
|
public List<ParameterDescriptor> Parameters { get; set; }
|
||||||
|
|
||||||
public List<IFilter> Filters { get; set; }
|
public List<FilterDescriptor> FilterDescriptors { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Filters
|
namespace Microsoft.AspNet.Mvc.Filters
|
||||||
{
|
{
|
||||||
// This one lives in the Filters namespace, and only intended to be consumed by folks that rewrite the action invoker.
|
// This one lives in the FilterDescriptors namespace, and only intended to be consumed by folks that rewrite the action invoker.
|
||||||
public class ReflectedActionFilterEndPoint : IActionFilter
|
public class ReflectedActionFilterEndPoint : IActionFilter
|
||||||
{
|
{
|
||||||
private readonly Func<object[], Task<object>> _coreMethodInvoker;
|
private readonly Func<object[], Task<object>> _coreMethodInvoker;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Filters
|
namespace Microsoft.AspNet.Mvc.Filters
|
||||||
{
|
{
|
||||||
// This one lives in the Filters namespace, and only intended to be consumed by folks that rewrite the action invoker.
|
// This one lives in the FilterDescriptors namespace, and only intended to be consumed by folks that rewrite the action invoker.
|
||||||
public class AuthorizationFilterEndPoint : IAuthorizationFilter
|
public class AuthorizationFilterEndPoint : IAuthorizationFilter
|
||||||
{
|
{
|
||||||
public bool EndPointCalled { get; private set; }
|
public bool EndPointCalled { get; private set; }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNet.DependencyInjection;
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Filters
|
namespace Microsoft.AspNet.Mvc.Filters
|
||||||
|
|
@ -12,28 +11,23 @@ namespace Microsoft.AspNet.Mvc.Filters
|
||||||
ServiceProvider = serviceProvider;
|
ServiceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public virtual void Invoke(FilterProviderContext context, Action callNext)
|
public virtual void Invoke(FilterProviderContext context, Action callNext)
|
||||||
{
|
{
|
||||||
List<IFilter> filters = context.ActionDescriptor.Filters;
|
FilterDescriptor[] filterDescriptors;
|
||||||
|
|
||||||
if (filters == null)
|
if (context.ActionDescriptor.FilterDescriptors != null)
|
||||||
{
|
{
|
||||||
filters = new List<IFilter>();
|
// make a copy of the list, TODO: Make the actiondescriptor immutable
|
||||||
}
|
filterDescriptors = context.ActionDescriptor.FilterDescriptors.ToArray();
|
||||||
else
|
|
||||||
{
|
|
||||||
filters = filters.ToList(); // make a copy of the list, TODO: Make the actiondescriptor immutable
|
|
||||||
|
|
||||||
}
|
//AddGlobalFilters_moveToAdPipeline(filters);
|
||||||
|
|
||||||
AddGlobalFilters(filters);
|
if (filterDescriptors.Length > 0)
|
||||||
|
|
||||||
if (filters.Count > 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < filters.Count; i++)
|
|
||||||
{
|
{
|
||||||
GetFilter(context, filters[i]);
|
for (int i = 0; i < filterDescriptors.Length; i++)
|
||||||
|
{
|
||||||
|
GetFilter(context, filterDescriptors[i].Filter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,66 +39,30 @@ namespace Microsoft.AspNet.Mvc.Filters
|
||||||
|
|
||||||
public virtual void GetFilter(FilterProviderContext context, IFilter filter)
|
public virtual void GetFilter(FilterProviderContext context, IFilter filter)
|
||||||
{
|
{
|
||||||
|
bool failIfNotFilter = true;
|
||||||
|
|
||||||
var serviceFilterSignature = filter as IServiceFilter;
|
var serviceFilterSignature = filter as IServiceFilter;
|
||||||
if (serviceFilterSignature != null)
|
if (serviceFilterSignature != null)
|
||||||
{
|
{
|
||||||
|
// TODO: How do we pass extra parameters
|
||||||
var serviceFilter = ServiceProvider.GetService(serviceFilterSignature.ServiceType);
|
var serviceFilter = ServiceProvider.GetService(serviceFilterSignature.ServiceType);
|
||||||
|
|
||||||
AddFilters(context, serviceFilter, true);
|
AddFilters(context, serviceFilter, true);
|
||||||
|
failIfNotFilter = false;
|
||||||
// if the filter implements more than the just IServiceFilter
|
|
||||||
AddFilters(context, filter, false);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
var typeFilterSignature = filter as ITypeFilter;
|
||||||
|
if (typeFilterSignature != null)
|
||||||
{
|
{
|
||||||
AddFilters(context, filter, true);
|
// TODO: How do we pass extra parameters
|
||||||
}
|
var typeFilter =
|
||||||
}
|
ServiceProvider.GetService<TypeActivator>().CreateInstance(typeFilterSignature.ImplementationType);
|
||||||
|
|
||||||
public virtual List<IFilter> AddGlobalFilters(List<IFilter> filters)
|
AddFilters(context, typeFilter, true);
|
||||||
{
|
failIfNotFilter = false;
|
||||||
var globalFilters = ServiceProvider.GetService<IEnumerable<IFilter>>().AsArray();
|
|
||||||
|
|
||||||
if (globalFilters == null || globalFilters.Length == 0)
|
|
||||||
{
|
|
||||||
return filters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return MergeSorted(filters, globalFilters);
|
AddFilters(context, filter, failIfNotFilter);
|
||||||
}
|
|
||||||
|
|
||||||
private List<IFilter> MergeSorted(List<IFilter> filtersFromAction, IFilter[] globalFilters)
|
|
||||||
{
|
|
||||||
if (globalFilters.Length == 0)
|
|
||||||
{
|
|
||||||
return filtersFromAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
var list = new List<IFilter>();
|
|
||||||
|
|
||||||
var count = filtersFromAction.Count + globalFilters.Length;
|
|
||||||
|
|
||||||
for (int i = 0, j = 0; i + j < count; )
|
|
||||||
{
|
|
||||||
if (i >= filtersFromAction.Count)
|
|
||||||
{
|
|
||||||
list.Add(globalFilters[j++]);
|
|
||||||
}
|
|
||||||
else if (j >= globalFilters.Length)
|
|
||||||
{
|
|
||||||
list.Add(filtersFromAction[i++]);
|
|
||||||
}
|
|
||||||
else if (filtersFromAction[i].Order >= globalFilters[j].Order)
|
|
||||||
{
|
|
||||||
list.Add(filtersFromAction[i++]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list.Add(globalFilters[j++]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IServiceProvider ServiceProvider { get; private set; }
|
protected IServiceProvider ServiceProvider { get; private set; }
|
||||||
|
|
@ -169,7 +127,7 @@ namespace Microsoft.AspNet.Mvc.Filters
|
||||||
|
|
||||||
if (shouldThrow)
|
if (shouldThrow)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Filter has to be IActionResultFilter, IActionFilter, IExceptionFilter or IAuthorizationFilter.");
|
throw new InvalidOperationException("Filter has to be IActionResultFilter, IActionFilter, IExceptionFilter or IAuthorizationFilter.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class FilterDescriptor
|
||||||
|
{
|
||||||
|
public FilterDescriptor([NotNull]IFilter filter, int origin)
|
||||||
|
{
|
||||||
|
Filter = filter;
|
||||||
|
Origin = origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IFilter Filter { get; private set; }
|
||||||
|
public int Origin { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class FilterDescriptorComparer : IComparer<FilterDescriptor>
|
||||||
|
{
|
||||||
|
private static FilterDescriptorComparer _comparer = new FilterDescriptorComparer();
|
||||||
|
|
||||||
|
public static FilterDescriptorComparer Comparer { get { return _comparer; } }
|
||||||
|
|
||||||
|
public int Compare([NotNull]FilterDescriptor x, [NotNull]FilterDescriptor y)
|
||||||
|
{
|
||||||
|
if (x.Filter.Order == y.Filter.Order)
|
||||||
|
{
|
||||||
|
return x.Origin.CompareTo(y.Origin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return x.Filter.Order.CompareTo(y.Filter.Order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public static class FilterOrigin
|
||||||
|
{
|
||||||
|
public static readonly int Action = 100;
|
||||||
|
public static readonly int Controlller = 200;
|
||||||
|
public static readonly int Global = 300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.Filters
|
||||||
private readonly IFilter<T>[] _filters;
|
private readonly IFilter<T>[] _filters;
|
||||||
private readonly T _context;
|
private readonly T _context;
|
||||||
|
|
||||||
// Filters are already ordered externally.
|
// FilterDescriptors are already ordered externally.
|
||||||
public FilterPipelineBuilder(IEnumerable<IFilter<T>> filters, T context)
|
public FilterPipelineBuilder(IEnumerable<IFilter<T>> filters, T context)
|
||||||
{
|
{
|
||||||
_filters = filters.ToArray();
|
_filters = filters.ToArray();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public interface ITypeFilter : IFilter
|
||||||
|
{
|
||||||
|
Type ImplementationType { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,16 +11,21 @@ namespace Microsoft.AspNet.Mvc
|
||||||
private readonly IActionDiscoveryConventions _conventions;
|
private readonly IActionDiscoveryConventions _conventions;
|
||||||
private readonly IControllerDescriptorFactory _controllerDescriptorFactory;
|
private readonly IControllerDescriptorFactory _controllerDescriptorFactory;
|
||||||
private readonly IParameterDescriptorFactory _parameterDescriptorFactory;
|
private readonly IParameterDescriptorFactory _parameterDescriptorFactory;
|
||||||
|
private readonly IEnumerable<FilterDescriptor> _globalFilters;
|
||||||
|
|
||||||
public ReflectedActionDescriptorProvider(IControllerAssemblyProvider controllerAssemblyProvider,
|
public ReflectedActionDescriptorProvider(IControllerAssemblyProvider controllerAssemblyProvider,
|
||||||
IActionDiscoveryConventions conventions,
|
IActionDiscoveryConventions conventions,
|
||||||
IControllerDescriptorFactory controllerDescriptorFactory,
|
IControllerDescriptorFactory controllerDescriptorFactory,
|
||||||
IParameterDescriptorFactory parameterDescriptorFactory)
|
IParameterDescriptorFactory parameterDescriptorFactory,
|
||||||
|
IEnumerable<IFilter> globalFilters)
|
||||||
{
|
{
|
||||||
_controllerAssemblyProvider = controllerAssemblyProvider;
|
_controllerAssemblyProvider = controllerAssemblyProvider;
|
||||||
_conventions = conventions;
|
_conventions = conventions;
|
||||||
_controllerDescriptorFactory = controllerDescriptorFactory;
|
_controllerDescriptorFactory = controllerDescriptorFactory;
|
||||||
_parameterDescriptorFactory = parameterDescriptorFactory;
|
_parameterDescriptorFactory = parameterDescriptorFactory;
|
||||||
|
var filters = globalFilters ?? Enumerable.Empty<IFilter>();
|
||||||
|
|
||||||
|
_globalFilters = filters.Select(f => new FilterDescriptor(f, FilterOrigin.Global));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Order
|
public int Order
|
||||||
|
|
@ -44,7 +49,12 @@ namespace Microsoft.AspNet.Mvc
|
||||||
foreach (var cd in controllerDescriptors)
|
foreach (var cd in controllerDescriptors)
|
||||||
{
|
{
|
||||||
var controllerAttributes = cd.ControllerTypeInfo.GetCustomAttributes(inherit: true).ToArray();
|
var controllerAttributes = cd.ControllerTypeInfo.GetCustomAttributes(inherit: true).ToArray();
|
||||||
var filtersFromController = GetOrderedFilterAttributes(controllerAttributes);
|
var globalAndControllerFilters =
|
||||||
|
controllerAttributes.OfType<IFilter>()
|
||||||
|
.Select(filter => new FilterDescriptor(filter, FilterOrigin.Controlller))
|
||||||
|
.Concat(_globalFilters)
|
||||||
|
.OrderBy(d => d, FilterDescriptorComparer.Comparer)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
foreach (var methodInfo in cd.ControllerTypeInfo.DeclaredMethods)
|
foreach (var methodInfo in cd.ControllerTypeInfo.DeclaredMethods)
|
||||||
{
|
{
|
||||||
|
|
@ -57,23 +67,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
foreach (var actionInfo in actionInfos)
|
foreach (var actionInfo in actionInfos)
|
||||||
{
|
{
|
||||||
yield return BuildDescriptor(cd, methodInfo, actionInfo, filtersFromController);
|
yield return BuildDescriptor(cd, methodInfo, actionInfo, globalAndControllerFilters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IFilter[] GetOrderedFilterAttributes(object[] attributes)
|
|
||||||
{
|
|
||||||
var filters = attributes.OfType<IFilter>().OrderByDescending(filter => filter.Order);
|
|
||||||
|
|
||||||
return filters.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReflectedActionDescriptor BuildDescriptor(ControllerDescriptor controllerDescriptor,
|
private ReflectedActionDescriptor BuildDescriptor(ControllerDescriptor controllerDescriptor,
|
||||||
MethodInfo methodInfo,
|
MethodInfo methodInfo,
|
||||||
ActionInfo actionInfo,
|
ActionInfo actionInfo,
|
||||||
IFilter[] controllerFilters)
|
FilterDescriptor[] globalAndControllerFilters)
|
||||||
{
|
{
|
||||||
var ad = new ReflectedActionDescriptor
|
var ad = new ReflectedActionDescriptor
|
||||||
{
|
{
|
||||||
|
|
@ -110,41 +113,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var attributes = methodInfo.GetCustomAttributes(inherit: true).ToArray();
|
var attributes = methodInfo.GetCustomAttributes(inherit: true).ToArray();
|
||||||
|
|
||||||
// TODO: add ordering support such that action filters are ahead of controller filters if they have the same order
|
// TODO: add ordering support such that action filters are ahead of controller filters if they have the same order
|
||||||
var filtersFromAction = GetOrderedFilterAttributes(attributes);
|
var filtersFromAction = attributes.OfType<IFilter>().Select(filter => new FilterDescriptor(filter, FilterOrigin.Action));
|
||||||
|
|
||||||
ad.Filters = MergeSorted(filtersFromAction, controllerFilters);
|
ad.FilterDescriptors = filtersFromAction.Concat(globalAndControllerFilters)
|
||||||
|
.OrderBy(d => d, FilterDescriptorComparer.Comparer)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
return ad;
|
return ad;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge filters, filters with the same order are prioritzed by origin action executes ahead of controller.
|
|
||||||
private List<IFilter> MergeSorted(IFilter[] filtersFromAction, IFilter[] filtersFromController)
|
|
||||||
{
|
|
||||||
var list = new List<IFilter>();
|
|
||||||
|
|
||||||
var count = filtersFromAction.Length + filtersFromController.Length;
|
|
||||||
|
|
||||||
for (int i = 0, j = 0; i + j < count; )
|
|
||||||
{
|
|
||||||
if (i >= filtersFromAction.Length)
|
|
||||||
{
|
|
||||||
list.Add(filtersFromController[j++]);
|
|
||||||
}
|
|
||||||
else if (j >= filtersFromController.Length)
|
|
||||||
{
|
|
||||||
list.Add(filtersFromAction[i++]);
|
|
||||||
}
|
|
||||||
else if (filtersFromAction[i].Order >= filtersFromController[j].Order)
|
|
||||||
{
|
|
||||||
list.Add(filtersFromAction[i++]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list.Add(filtersFromController[j++]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue