Filter discovery
This commit is contained in:
parent
dc6b1b1a4a
commit
75bccbae21
|
|
@ -0,0 +1,21 @@
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
using MvcSample.Models;
|
||||||
|
|
||||||
|
namespace MvcSample
|
||||||
|
{
|
||||||
|
// Expected order in descriptor - object -> int -> string
|
||||||
|
// TODO: Add a real filter here
|
||||||
|
[ServiceFilter(typeof(object), Order = 1)]
|
||||||
|
[ServiceFilter(typeof(string))]
|
||||||
|
public class FiltersController : Controller
|
||||||
|
{
|
||||||
|
private readonly User _user = new User() { Name = "User Name", Address = "Home Address" };
|
||||||
|
|
||||||
|
// TODO: Add a real filter here
|
||||||
|
[ServiceFilter(typeof(int))]
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
return View("MyView", _user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,5 +3,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public interface IFilter
|
public interface IFilter
|
||||||
{
|
{
|
||||||
// Marker only interface to any IFilter gets picked up by the DefaultActionDescriptorProvider
|
// Marker only interface to any IFilter gets picked up by the DefaultActionDescriptorProvider
|
||||||
|
int Order { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public interface IServiceFilter : IFilter
|
||||||
|
{
|
||||||
|
Type ServiceType { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||||
|
[DebuggerDisplay("ServiceFilter: Type={ServiceType} Order={Order}")]
|
||||||
|
public class ServiceFilterAttribute : Attribute, IServiceFilter
|
||||||
|
{
|
||||||
|
public ServiceFilterAttribute(Type type)
|
||||||
|
{
|
||||||
|
ServiceType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type ServiceType { get; private set; }
|
||||||
|
|
||||||
|
public int Order { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -43,6 +43,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
foreach (var cd in controllerDescriptors)
|
foreach (var cd in controllerDescriptors)
|
||||||
{
|
{
|
||||||
|
var controllerFilters = GetOrderedFilterAttributes(cd.ControllerTypeInfo);
|
||||||
|
|
||||||
foreach (var methodInfo in cd.ControllerTypeInfo.DeclaredMethods)
|
foreach (var methodInfo in cd.ControllerTypeInfo.DeclaredMethods)
|
||||||
{
|
{
|
||||||
var actionInfos = _conventions.GetActions(methodInfo);
|
var actionInfos = _conventions.GetActions(methodInfo);
|
||||||
|
|
@ -54,13 +56,24 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
foreach (var actionInfo in actionInfos)
|
foreach (var actionInfo in actionInfos)
|
||||||
{
|
{
|
||||||
yield return BuildDescriptor(cd, methodInfo, actionInfo);
|
yield return BuildDescriptor(cd, methodInfo, actionInfo, controllerFilters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReflectedActionDescriptor BuildDescriptor(ControllerDescriptor controllerDescriptor, MethodInfo methodInfo, ActionInfo actionInfo)
|
private IFilter[] GetOrderedFilterAttributes(MemberInfo memberInfo)
|
||||||
|
{
|
||||||
|
var attributes = memberInfo.GetCustomAttributes(inherit: true);
|
||||||
|
var filters = attributes.OfType<IFilter>().OrderByDescending(filter => filter.Order);
|
||||||
|
|
||||||
|
return filters.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReflectedActionDescriptor BuildDescriptor(ControllerDescriptor controllerDescriptor,
|
||||||
|
MethodInfo methodInfo,
|
||||||
|
ActionInfo actionInfo,
|
||||||
|
IFilter[] controllerFilters)
|
||||||
{
|
{
|
||||||
var ad = new ReflectedActionDescriptor
|
var ad = new ReflectedActionDescriptor
|
||||||
{
|
{
|
||||||
|
|
@ -85,7 +98,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
if (actionInfo.RequireActionNameMatch)
|
if (actionInfo.RequireActionNameMatch)
|
||||||
{
|
{
|
||||||
ad.RouteConstraints.Add(new RouteDataActionConstraint("action", actionInfo.ActionName));
|
ad.RouteConstraints.Add(new RouteDataActionConstraint("action", actionInfo.ActionName));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -94,7 +107,41 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
ad.Parameters = methodInfo.GetParameters().Select(p => _parameterDescriptorFactory.GetDescriptor(p)).ToList();
|
ad.Parameters = methodInfo.GetParameters().Select(p => _parameterDescriptorFactory.GetDescriptor(p)).ToList();
|
||||||
|
|
||||||
|
// TODO: add ordering support such that action filters are ahead of controller filters if they have the same order
|
||||||
|
var actionFilters = GetOrderedFilterAttributes(methodInfo);
|
||||||
|
|
||||||
|
ad.Filters = MergeSorted(actionFilters, controllerFilters);
|
||||||
|
|
||||||
return ad;
|
return ad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal List<IFilter> MergeSorted(IFilter[] actionFilters, IFilter[] controllerFilters)
|
||||||
|
{
|
||||||
|
var list = new List<IFilter>();
|
||||||
|
|
||||||
|
var count = actionFilters.Length + controllerFilters.Length;
|
||||||
|
|
||||||
|
for (int i = 0, j = 0; i + j < count; )
|
||||||
|
{
|
||||||
|
if (i >= actionFilters.Length)
|
||||||
|
{
|
||||||
|
list.Add(controllerFilters[j++]);
|
||||||
|
}
|
||||||
|
else if (j >= controllerFilters.Length)
|
||||||
|
{
|
||||||
|
list.Add(actionFilters[i++]);
|
||||||
|
}
|
||||||
|
else if (actionFilters[i].Order >= controllerFilters[j].Order)
|
||||||
|
{
|
||||||
|
list.Add(actionFilters[i++]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list.Add(controllerFilters[j++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue