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<IFilter> Filters { get; set; }
|
||||
public List<FilterDescriptor> FilterDescriptors { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using System.Threading.Tasks;
|
|||
|
||||
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
|
||||
{
|
||||
private readonly Func<object[], Task<object>> _coreMethodInvoker;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using System.Threading.Tasks;
|
|||
|
||||
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 bool EndPointCalled { get; private set; }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Filters
|
||||
|
|
@ -12,28 +11,23 @@ namespace Microsoft.AspNet.Mvc.Filters
|
|||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
|
||||
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>();
|
||||
}
|
||||
else
|
||||
{
|
||||
filters = filters.ToList(); // make a copy of the list, TODO: Make the actiondescriptor immutable
|
||||
// make a copy of the list, TODO: Make the actiondescriptor immutable
|
||||
filterDescriptors = context.ActionDescriptor.FilterDescriptors.ToArray();
|
||||
|
||||
}
|
||||
//AddGlobalFilters_moveToAdPipeline(filters);
|
||||
|
||||
AddGlobalFilters(filters);
|
||||
|
||||
if (filters.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < filters.Count; i++)
|
||||
if (filterDescriptors.Length > 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
bool failIfNotFilter = true;
|
||||
|
||||
var serviceFilterSignature = filter as IServiceFilter;
|
||||
if (serviceFilterSignature != null)
|
||||
{
|
||||
// TODO: How do we pass extra parameters
|
||||
var serviceFilter = ServiceProvider.GetService(serviceFilterSignature.ServiceType);
|
||||
|
||||
AddFilters(context, serviceFilter, true);
|
||||
|
||||
// if the filter implements more than the just IServiceFilter
|
||||
AddFilters(context, filter, false);
|
||||
failIfNotFilter = 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)
|
||||
{
|
||||
var globalFilters = ServiceProvider.GetService<IEnumerable<IFilter>>().AsArray();
|
||||
|
||||
if (globalFilters == null || globalFilters.Length == 0)
|
||||
{
|
||||
return filters;
|
||||
AddFilters(context, typeFilter, true);
|
||||
failIfNotFilter = false;
|
||||
}
|
||||
|
||||
return MergeSorted(filters, globalFilters);
|
||||
}
|
||||
|
||||
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;
|
||||
AddFilters(context, filter, failIfNotFilter);
|
||||
}
|
||||
|
||||
protected IServiceProvider ServiceProvider { get; private set; }
|
||||
|
|
@ -169,7 +127,7 @@ namespace Microsoft.AspNet.Mvc.Filters
|
|||
|
||||
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 T _context;
|
||||
|
||||
// Filters are already ordered externally.
|
||||
// FilterDescriptors are already ordered externally.
|
||||
public FilterPipelineBuilder(IEnumerable<IFilter<T>> filters, T context)
|
||||
{
|
||||
_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 IControllerDescriptorFactory _controllerDescriptorFactory;
|
||||
private readonly IParameterDescriptorFactory _parameterDescriptorFactory;
|
||||
private readonly IEnumerable<FilterDescriptor> _globalFilters;
|
||||
|
||||
public ReflectedActionDescriptorProvider(IControllerAssemblyProvider controllerAssemblyProvider,
|
||||
IActionDiscoveryConventions conventions,
|
||||
IControllerDescriptorFactory controllerDescriptorFactory,
|
||||
IParameterDescriptorFactory parameterDescriptorFactory)
|
||||
IParameterDescriptorFactory parameterDescriptorFactory,
|
||||
IEnumerable<IFilter> globalFilters)
|
||||
{
|
||||
_controllerAssemblyProvider = controllerAssemblyProvider;
|
||||
_conventions = conventions;
|
||||
_controllerDescriptorFactory = controllerDescriptorFactory;
|
||||
_parameterDescriptorFactory = parameterDescriptorFactory;
|
||||
var filters = globalFilters ?? Enumerable.Empty<IFilter>();
|
||||
|
||||
_globalFilters = filters.Select(f => new FilterDescriptor(f, FilterOrigin.Global));
|
||||
}
|
||||
|
||||
public int Order
|
||||
|
|
@ -44,7 +49,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
foreach (var cd in controllerDescriptors)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
@ -57,23 +67,16 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
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,
|
||||
MethodInfo methodInfo,
|
||||
ActionInfo actionInfo,
|
||||
IFilter[] controllerFilters)
|
||||
FilterDescriptor[] globalAndControllerFilters)
|
||||
{
|
||||
var ad = new ReflectedActionDescriptor
|
||||
{
|
||||
|
|
@ -110,41 +113,13 @@ namespace Microsoft.AspNet.Mvc
|
|||
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
|
||||
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;
|
||||
}
|
||||
|
||||
// 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