Default filter provider, instantiates and merges all filters pre action invocation.
This commit is contained in:
parent
4bb66937e3
commit
4d90d590a9
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -8,15 +9,19 @@ namespace Microsoft.AspNet.Mvc
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly IControllerFactory _controllerFactory;
|
private readonly IControllerFactory _controllerFactory;
|
||||||
private readonly IActionBindingContextProvider _bindingProvider;
|
private readonly IActionBindingContextProvider _bindingProvider;
|
||||||
|
private readonly INestedProviderManager<FilterProviderContext> _filterProvider;
|
||||||
|
|
||||||
|
|
||||||
public ActionInvokerProvider(IActionResultFactory actionResultFactory,
|
public ActionInvokerProvider(IActionResultFactory actionResultFactory,
|
||||||
IControllerFactory controllerFactory,
|
IControllerFactory controllerFactory,
|
||||||
IActionBindingContextProvider bindingProvider,
|
IActionBindingContextProvider bindingProvider,
|
||||||
|
INestedProviderManager<FilterProviderContext> filterProvider,
|
||||||
IServiceProvider serviceProvider)
|
IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
_actionResultFactory = actionResultFactory;
|
_actionResultFactory = actionResultFactory;
|
||||||
_controllerFactory = controllerFactory;
|
_controllerFactory = controllerFactory;
|
||||||
_bindingProvider = bindingProvider;
|
_bindingProvider = bindingProvider;
|
||||||
|
_filterProvider = filterProvider;
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,6 +42,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
_actionResultFactory,
|
_actionResultFactory,
|
||||||
_controllerFactory,
|
_controllerFactory,
|
||||||
_bindingProvider,
|
_bindingProvider,
|
||||||
|
_filterProvider,
|
||||||
_serviceProvider);
|
_serviceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class DefaultFilterProvider : INestedProvider<FilterProviderContext>
|
||||||
|
{
|
||||||
|
public DefaultFilterProvider(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
ServiceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public virtual void Invoke(FilterProviderContext context, Action callNext)
|
||||||
|
{
|
||||||
|
List<IFilter> filters = context.ActionDescriptor.Filters;
|
||||||
|
|
||||||
|
if (filters == null)
|
||||||
|
{
|
||||||
|
filters = new List<IFilter>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filters = filters.ToList(); // make a copy of the list, TODO: Make the actiondescriptor immutable
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AddGlobalFilters(filters);
|
||||||
|
|
||||||
|
if (filters.Count > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < filters.Count; i++)
|
||||||
|
{
|
||||||
|
GetFilter(context, filters[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callNext != null)
|
||||||
|
{
|
||||||
|
callNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void GetFilter(FilterProviderContext context, IFilter filter)
|
||||||
|
{
|
||||||
|
var serviceFilterSignature = filter as IServiceFilter;
|
||||||
|
if (serviceFilterSignature != null)
|
||||||
|
{
|
||||||
|
var serviceFilter = ServiceProvider.GetService(serviceFilterSignature.ServiceType);
|
||||||
|
|
||||||
|
AddFilters(context, serviceFilter, true);
|
||||||
|
|
||||||
|
// if the filter implements more than the just IServiceFilter
|
||||||
|
AddFilters(context, filter, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddFilters(context, filter, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual List<IFilter> AddGlobalFilters(List<IFilter> filters)
|
||||||
|
{
|
||||||
|
var globalFilters = ServiceProvider.GetService<IEnumerable<IFilter>>().AsArray();
|
||||||
|
|
||||||
|
if (globalFilters == null || globalFilters.Length == 0)
|
||||||
|
{
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IServiceProvider ServiceProvider { get; private set; }
|
||||||
|
|
||||||
|
public int Order
|
||||||
|
{
|
||||||
|
get { return 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddFilters(FilterProviderContext context, object filter, bool throwIfNotFilter)
|
||||||
|
{
|
||||||
|
bool shouldThrow = throwIfNotFilter;
|
||||||
|
|
||||||
|
var authFilter = filter as IAuthorizationFilter;
|
||||||
|
var actionFilter = filter as IActionFilter;
|
||||||
|
var actionResultFilter = filter as IActionResultFilter;
|
||||||
|
var exceptionFilter = filter as IExceptionFilter;
|
||||||
|
|
||||||
|
if (authFilter != null)
|
||||||
|
{
|
||||||
|
if (context.AuthorizationFilters == null)
|
||||||
|
{
|
||||||
|
context.AuthorizationFilters = new List<IAuthorizationFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.AuthorizationFilters.Add(authFilter);
|
||||||
|
shouldThrow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionFilter != null)
|
||||||
|
{
|
||||||
|
if (context.ActionFilters == null)
|
||||||
|
{
|
||||||
|
context.ActionFilters = new List<IActionFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.ActionFilters.Add(actionFilter);
|
||||||
|
shouldThrow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionResultFilter != null)
|
||||||
|
{
|
||||||
|
if (context.ActionResultFilters == null)
|
||||||
|
{
|
||||||
|
context.ActionResultFilters = new List<IActionResultFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.ActionResultFilters.Add(actionResultFilter);
|
||||||
|
shouldThrow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exceptionFilter != null)
|
||||||
|
{
|
||||||
|
if (context.ExceptionFilters == null)
|
||||||
|
{
|
||||||
|
context.ExceptionFilters = new List<IExceptionFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.ExceptionFilters.Add(exceptionFilter);
|
||||||
|
shouldThrow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldThrow)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Filter has to be IActionResultFilter, IActionFilter, IExceptionFilter or IAuthorizationFilter.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class FilterProviderContext
|
||||||
|
{
|
||||||
|
public FilterProviderContext(ActionDescriptor actionDescriptor)
|
||||||
|
{
|
||||||
|
ActionDescriptor = actionDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input
|
||||||
|
public ActionDescriptor ActionDescriptor { get; set; }
|
||||||
|
|
||||||
|
// Results
|
||||||
|
public List<IAuthorizationFilter> AuthorizationFilters { get; set; }
|
||||||
|
|
||||||
|
public List<IActionFilter> ActionFilters { get; set; }
|
||||||
|
|
||||||
|
public List<IActionResultFilter> ActionResultFilters { get; set; }
|
||||||
|
|
||||||
|
public List<IExceptionFilter> ExceptionFilters { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Abstractions;
|
using Microsoft.AspNet.Abstractions;
|
||||||
using Microsoft.AspNet.Mvc.Internal;
|
using Microsoft.AspNet.Mvc.Internal;
|
||||||
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
|
@ -17,12 +18,14 @@ namespace Microsoft.AspNet.Mvc
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly IControllerFactory _controllerFactory;
|
private readonly IControllerFactory _controllerFactory;
|
||||||
private readonly IActionBindingContextProvider _bindingProvider;
|
private readonly IActionBindingContextProvider _bindingProvider;
|
||||||
|
private readonly INestedProviderManager<FilterProviderContext> _filterProvider;
|
||||||
|
|
||||||
public ReflectedActionInvoker(ActionContext actionContext,
|
public ReflectedActionInvoker(ActionContext actionContext,
|
||||||
ReflectedActionDescriptor descriptor,
|
ReflectedActionDescriptor descriptor,
|
||||||
IActionResultFactory actionResultFactory,
|
IActionResultFactory actionResultFactory,
|
||||||
IControllerFactory controllerFactory,
|
IControllerFactory controllerFactory,
|
||||||
IActionBindingContextProvider bindingContextProvider,
|
IActionBindingContextProvider bindingContextProvider,
|
||||||
|
INestedProviderManager<FilterProviderContext> filterProvider,
|
||||||
IServiceProvider serviceProvider)
|
IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
_actionContext = actionContext;
|
_actionContext = actionContext;
|
||||||
|
|
@ -30,6 +33,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
_actionResultFactory = actionResultFactory;
|
_actionResultFactory = actionResultFactory;
|
||||||
_controllerFactory = controllerFactory;
|
_controllerFactory = controllerFactory;
|
||||||
_bindingProvider = bindingContextProvider;
|
_bindingProvider = bindingContextProvider;
|
||||||
|
_filterProvider = filterProvider;
|
||||||
|
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,8 +61,12 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
var parameterValues = await GetParameterValues(modelState);
|
var parameterValues = await GetParameterValues(modelState);
|
||||||
|
|
||||||
|
var context = new FilterProviderContext(_descriptor);
|
||||||
|
_filterProvider.Invoke(context);
|
||||||
|
|
||||||
object actionReturnValue = method.Invoke(controller, GetArgumentValues(parameterValues));
|
object actionReturnValue = method.Invoke(controller, GetArgumentValues(parameterValues));
|
||||||
|
|
||||||
|
|
||||||
actionResult = _actionResultFactory.CreateActionResult(method.ReturnType, actionReturnValue, _actionContext);
|
actionResult = _actionResultFactory.CreateActionResult(method.ReturnType, actionReturnValue, _actionContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
yield return DescribeService<IModelBinder, MutableObjectModelBinder>(configuration);
|
yield return DescribeService<IModelBinder, MutableObjectModelBinder>(configuration);
|
||||||
yield return DescribeService<IModelBinder, ComplexModelDtoModelBinder>(configuration);
|
yield return DescribeService<IModelBinder, ComplexModelDtoModelBinder>(configuration);
|
||||||
|
|
||||||
|
yield return DescribeService<INestedProviderManager<FilterProviderContext>, NestedProviderManager<FilterProviderContext>>(configuration);
|
||||||
|
yield return DescribeService<INestedProvider<FilterProviderContext>, DefaultFilterProvider>(configuration);
|
||||||
|
|
||||||
yield return DescribeService<IInputFormatter, JsonInputFormatter>(configuration);
|
yield return DescribeService<IInputFormatter, JsonInputFormatter>(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,6 +93,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
var serviceTypeName = serviceType.FullName;
|
var serviceTypeName = serviceType.FullName;
|
||||||
var implementationTypeName = configuration.Get(serviceTypeName);
|
var implementationTypeName = configuration.Get(serviceTypeName);
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(implementationTypeName))
|
if (!String.IsNullOrEmpty(implementationTypeName))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue