Filter execution
This commit is contained in:
parent
f669c1c00e
commit
6fed92695b
|
|
@ -25,9 +25,9 @@ namespace MvcSample
|
|||
|
||||
public class PassThroughAttribute : AuthorizationFilterAttribute
|
||||
{
|
||||
public async override Task Invoke(AuthorizationFilterContext context, Func<AuthorizationFilterContext, Task> next)
|
||||
public async override Task Invoke(AuthorizationFilterContext context, Func<Task> next)
|
||||
{
|
||||
await next(context);
|
||||
await next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public abstract class ActionFilterAttribute : Attribute, IActionFilter, IFilter
|
||||
{
|
||||
public abstract Task Invoke(ActionFilterContext context, Func<ActionFilterContext, Task> next);
|
||||
public abstract Task Invoke(ActionFilterContext context, Func<Task> next);
|
||||
|
||||
public int Order { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
|
|
@ -14,6 +15,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
public virtual ActionContext ActionContext { get; private set; }
|
||||
|
||||
public virtual IActionResult Result { get; set; }
|
||||
public virtual Type MethodReturnType { get; private set; }
|
||||
|
||||
public virtual object Result { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Filters
|
||||
{
|
||||
public class ReflectedActionFilterEndPoint : IActionFilter
|
||||
{
|
||||
private readonly Func<object[], Task<object>> _coreMethodInvoker;
|
||||
private readonly IActionResultFactory _actionResultFactory;
|
||||
|
||||
public ReflectedActionFilterEndPoint(Func<object[], Task<object>> coreMethodInvoker,
|
||||
IActionResultFactory actionResultFactory)
|
||||
{
|
||||
_coreMethodInvoker = coreMethodInvoker;
|
||||
_actionResultFactory = actionResultFactory;
|
||||
}
|
||||
|
||||
public async Task Invoke(ActionFilterContext context, Func<Task> next)
|
||||
{
|
||||
// TODO: match the parameter names here.
|
||||
var tempArray = context.ActionParameters.Values.ToArray(); // seriously broken for now, need to organize names to match.
|
||||
|
||||
var actionReturnValue = await _coreMethodInvoker(tempArray);
|
||||
|
||||
context.Result = _actionResultFactory.CreateActionResult(context.MethodReturnType,
|
||||
actionReturnValue,
|
||||
context.ActionContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public abstract class ActionResultFilterAttribute : Attribute, IActionResultFilter, IFilter
|
||||
{
|
||||
public abstract Task Invoke(ActionResultFilterContext context, Func<ActionResultFilterContext, Task> next);
|
||||
public abstract Task Invoke(ActionResultFilterContext context, Func<Task> next);
|
||||
|
||||
public int Order { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
{
|
||||
public class ActionResultFilterContext
|
||||
{
|
||||
public ActionResultFilterContext(ActionContext actionContext)
|
||||
public ActionResultFilterContext(ActionContext actionContext, IActionResult initialResult)
|
||||
{
|
||||
ActionContext = actionContext;
|
||||
Result = initialResult;
|
||||
}
|
||||
|
||||
public ActionContext ActionContext { get; private set; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Filters
|
||||
{
|
||||
public class ActionResultFilterEndPoint : IActionResultFilter
|
||||
{
|
||||
public async Task Invoke(ActionResultFilterContext context, Func<Task> next)
|
||||
{
|
||||
await context.Result.ExecuteResultAsync(context.ActionContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public abstract class AuthorizationFilterAttribute : Attribute, IFilter, IAuthorizationFilter
|
||||
{
|
||||
public abstract Task Invoke(AuthorizationFilterContext context, Func<AuthorizationFilterContext, Task> next);
|
||||
public abstract Task Invoke(AuthorizationFilterContext context, Func<Task> next);
|
||||
|
||||
public int Order { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Filters
|
||||
{
|
||||
public class AuthorizationFilterEndPoint : IAuthorizationFilter
|
||||
{
|
||||
public bool EndPointCalled { get; private set; }
|
||||
|
||||
public Task Invoke(AuthorizationFilterContext context, Func<Task> next)
|
||||
{
|
||||
EndPointCalled = true;
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public abstract class ExceptionFilterAttribute : Attribute, IExceptionFilter, IFilter
|
||||
{
|
||||
public abstract Task Invoke(ExceptionFilterContext context, Func<ExceptionFilterContext, Task> next);
|
||||
public abstract Task Invoke(ExceptionFilterContext context, Func<Task> next);
|
||||
|
||||
public int Order { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Filters
|
||||
{
|
||||
public class FilterPipelineBuilder<T>
|
||||
{
|
||||
private readonly IFilter<T>[] _filters;
|
||||
private readonly T _context;
|
||||
|
||||
// Filters are already ordered externally.
|
||||
public FilterPipelineBuilder(IEnumerable<IFilter<T>> filters, T context)
|
||||
{
|
||||
_filters = filters.ToArray();
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync()
|
||||
{
|
||||
var caller = new CallNextAsync(_context, _filters);
|
||||
|
||||
await caller.CallNextProvider();
|
||||
}
|
||||
|
||||
private class CallNextAsync
|
||||
{
|
||||
private readonly T _context;
|
||||
private readonly IFilter<T>[] _filters;
|
||||
private readonly Func<Task> _next;
|
||||
|
||||
private int _index;
|
||||
|
||||
public CallNextAsync(T context, IFilter<T>[] filters)
|
||||
{
|
||||
_context = context;
|
||||
_next = CallNextProvider;
|
||||
_filters = filters;
|
||||
}
|
||||
|
||||
public async Task CallNextProvider()
|
||||
{
|
||||
if (_filters.Length > _index)
|
||||
{
|
||||
await _filters[_index++].Invoke(_context, _next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,6 @@ namespace Microsoft.AspNet.Mvc.Filters
|
|||
{
|
||||
public interface IFilter<T>
|
||||
{
|
||||
Task Invoke(T context, Func<T, Task> next);
|
||||
Task Invoke(T context, Func<Task> next);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ using Microsoft.AspNet.Abstractions;
|
|||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Microsoft.AspNet.DependencyInjection;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.DependencyInjection.NestedProviders;
|
||||
using Microsoft.AspNet.Mvc.Filters;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
|
|
@ -41,6 +43,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
public async Task InvokeActionAsync()
|
||||
{
|
||||
IActionResult actionResult;
|
||||
var context = new FilterProviderContext(_descriptor);
|
||||
_filterProvider.Invoke(context);
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
object controller = _controllerFactory.CreateController(_actionContext, modelState);
|
||||
|
|
@ -61,18 +65,53 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
var parameterValues = await GetParameterValues(modelState);
|
||||
|
||||
var context = new FilterProviderContext(_descriptor);
|
||||
_filterProvider.Invoke(context);
|
||||
var authZFilters = context.AuthorizationFilters;
|
||||
var authZEndPoint = new AuthorizationFilterEndPoint();
|
||||
authZFilters.Add(authZEndPoint);
|
||||
var authZContext = new AuthorizationFilterContext(_actionContext);
|
||||
var authZPipeline = new FilterPipelineBuilder<AuthorizationFilterContext>(authZFilters, authZContext);
|
||||
|
||||
object actionReturnValue = method.Invoke(controller, GetArgumentValues(parameterValues));
|
||||
await authZPipeline.InvokeAsync();
|
||||
|
||||
|
||||
if (authZContext.ActionResult == null &&
|
||||
!authZContext.HasFailed &&
|
||||
authZEndPoint.EndPointCalled)
|
||||
{
|
||||
var actionFilters = context.ActionFilters;
|
||||
var actionFilterContext = new ActionFilterContext(_actionContext,
|
||||
new Dictionary<string, object>());
|
||||
|
||||
actionResult = _actionResultFactory.CreateActionResult(method.ReturnType, actionReturnValue, _actionContext);
|
||||
// TODO: This is extremely temporary and is going to get soon replaced with the action executer
|
||||
var actionEndPoint = new ReflectedActionFilterEndPoint(async (inArray) => method.Invoke(controller, inArray),
|
||||
_actionResultFactory);
|
||||
|
||||
actionFilters.Add(actionEndPoint);
|
||||
|
||||
var actionFilterPipeline = new FilterPipelineBuilder<ActionFilterContext>(actionFilters,
|
||||
actionFilterContext);
|
||||
|
||||
await actionFilterPipeline.InvokeAsync();
|
||||
|
||||
object actionReturnValue = method.Invoke(controller, null);
|
||||
actionResult = _actionResultFactory.CreateActionResult(method.ReturnType, actionReturnValue, _actionContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
actionResult = authZContext.ActionResult ?? new HttpStatusCodeResult(401);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This will probably move out once we got filters
|
||||
var actionResultFilters = context.ActionResultFilters;
|
||||
await actionResult.ExecuteResultAsync(_actionContext);
|
||||
var actionResultFilterContext = new ActionResultFilterContext(_actionContext, actionResult);
|
||||
var actionResultFilterEndPoint = new ActionResultFilterEndPoint();
|
||||
actionResultFilters.Add(actionResultFilterEndPoint);
|
||||
|
||||
var actionResultPipeline = new FilterPipelineBuilder<ActionResultFilterContext>(actionResultFilters, actionResultFilterContext);
|
||||
|
||||
await actionResultPipeline.InvokeAsync();
|
||||
}
|
||||
|
||||
private async Task<IDictionary<string, object>> GetParameterValues(ModelStateDictionary modelState)
|
||||
|
|
|
|||
Loading…
Reference in New Issue