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 Microsoft.AspNet.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
|
|
@ -8,15 +9,19 @@ namespace Microsoft.AspNet.Mvc
|
|||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IControllerFactory _controllerFactory;
|
||||
private readonly IActionBindingContextProvider _bindingProvider;
|
||||
private readonly INestedProviderManager<FilterProviderContext> _filterProvider;
|
||||
|
||||
|
||||
public ActionInvokerProvider(IActionResultFactory actionResultFactory,
|
||||
IControllerFactory controllerFactory,
|
||||
IActionBindingContextProvider bindingProvider,
|
||||
INestedProviderManager<FilterProviderContext> filterProvider,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
_actionResultFactory = actionResultFactory;
|
||||
_controllerFactory = controllerFactory;
|
||||
_bindingProvider = bindingProvider;
|
||||
_filterProvider = filterProvider;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
|
|
@ -37,6 +42,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
_actionResultFactory,
|
||||
_controllerFactory,
|
||||
_bindingProvider,
|
||||
_filterProvider,
|
||||
_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 Microsoft.AspNet.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Microsoft.AspNet.DependencyInjection;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
|
|
@ -17,12 +18,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IControllerFactory _controllerFactory;
|
||||
private readonly IActionBindingContextProvider _bindingProvider;
|
||||
private readonly INestedProviderManager<FilterProviderContext> _filterProvider;
|
||||
|
||||
public ReflectedActionInvoker(ActionContext actionContext,
|
||||
ReflectedActionDescriptor descriptor,
|
||||
IActionResultFactory actionResultFactory,
|
||||
IControllerFactory controllerFactory,
|
||||
IActionBindingContextProvider bindingContextProvider,
|
||||
INestedProviderManager<FilterProviderContext> filterProvider,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
_actionContext = actionContext;
|
||||
|
|
@ -30,6 +33,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
_actionResultFactory = actionResultFactory;
|
||||
_controllerFactory = controllerFactory;
|
||||
_bindingProvider = bindingContextProvider;
|
||||
_filterProvider = filterProvider;
|
||||
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
|
|
@ -56,8 +61,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
var parameterValues = await GetParameterValues(modelState);
|
||||
|
||||
var context = new FilterProviderContext(_descriptor);
|
||||
_filterProvider.Invoke(context);
|
||||
|
||||
object actionReturnValue = method.Invoke(controller, GetArgumentValues(parameterValues));
|
||||
|
||||
|
||||
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, ComplexModelDtoModelBinder>(configuration);
|
||||
|
||||
yield return DescribeService<INestedProviderManager<FilterProviderContext>, NestedProviderManager<FilterProviderContext>>(configuration);
|
||||
yield return DescribeService<INestedProvider<FilterProviderContext>, DefaultFilterProvider>(configuration);
|
||||
|
||||
yield return DescribeService<IInputFormatter, JsonInputFormatter>(configuration);
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +93,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
var serviceTypeName = serviceType.FullName;
|
||||
var implementationTypeName = configuration.Get(serviceTypeName);
|
||||
|
||||
if (!String.IsNullOrEmpty(implementationTypeName))
|
||||
{
|
||||
try
|
||||
|
|
|
|||
Loading…
Reference in New Issue