从实现上说,ControllerActionInvoker
其实是ResourceInvoker
的子类。其InvokeAsync()
方法的主要流程就是调用InvokeFilterPipelineAsync()
。
ResourceInvoker
ResourceInvoker
中的Resource
含义和Resource filters
中的含义相同。但是这里的ResourceInvoker
会负责调用整个Filter
管道,主要包括Authorization Filters
(2.x
)、Exception Filters
、Model Binding
、Action Filters
、及Result Filters
的全部过程:
public virtual async Task InvokeAsync()
{
try{
//.. diagnose;
using (_logger.ActionScope(_actionContext.ActionDescriptor)){
// ... log
try {
await InvokeFilterPipelineAsync();
} finally{
ReleaseResources();
// ... log
}
}
} finally {
//.. diagnose;
}
}
显然,这里的InvokeFilterPipelineAsync()
是整个方法的核心,该方法会不停地尝试调用自身的一个Next
方法,直至结束:
private async Task InvokeFilterPipelineAsync()
{
var next = State.InvokeBegin;
// The `scope` tells the `Next` method who the caller is, and what kind of state to initialize to
// communicate a result. The outermost scope is `Scope.Invoker` and doesn't require any type
// of context or result other than throwing.
var scope = Scope.Invoker;
// The `state` is used for internal state handling during transitions between states. In practice this
// means storing a filter instance in `state` and then retrieving it in the next state.
var state = (object)null;
// `isCompleted` will be set to true when we've reached a terminal state.
var isCompleted = false;
while (!isCompleted)
{
await Next(ref next, ref scope, ref state, ref isCompleted);
}
}
protected abstract Task InvokeInnerFilterAsync();
而Next()
方法负责依次调用管道内的Filter
。对于具体的Action Filters
及Action
本身的调用,则交由抽象方法InvokeInnerFilterAsync()
定义,延迟到子类中实现。
ASP.NET Core
中内置的ResourceInvoker
实现有ControllerActionInvoker
和PageActionInvoker
,分别负责对MVC
中Action
进行调用和对RazorPage
的handler
进行调用。
ControllerActionInvoker
ControllerActionInvoker
对父类抽象方法InvokeInnerFilterAsync()
的实现是也是通过状态机实现,如果是同步调用,大致的流程是:
filter.OnActionExecuting()
,InvokeActionMethodAsync()
,filter.OnActionExecuted()
事实上,ASP.NET Core MVC
中内置的Controller
抽象类自身也是一个IActionFilter
:
public abstract class Controller : ControllerBase, IActionFilter, IAsyncActionFilter, IDisposable
{
...
[NonAction] public virtual void OnActionExecuting(ActionExecutingContext context) { }
[NonAction] public virtual void OnActionExecuted(ActionExecutedContext context){ }
[NonAction] public virtual Task OnActionExecutionAsync( ActionExecutingContext context, ActionExecutionDelegate next)
{
if (context == null) { /* throw */; }
if (next == null) { /* throw */; }
OnActionExecuting(context);
if (context.Result == null)
{
var task = next();
if (!task.IsCompletedSuccessfully)
{
return Awaited(this, task);
}
OnActionExecuted(task.Result);
}
return Task.CompletedTask;
static async Task Awaited(Controller controller, Task<ActionExecutedContext> task){ controller.OnActionExecuted(await task); }
}
...
}
可以看到,这里Controller::OnActionExecutionAsync(ctx,next)
方法会按如下顺序依次调用:
OnActionExecuting(executingContext)
方法next()
委托,也就是Action
方法本身OnActionExecuted(executedContext)
方法和普通的ActionFilter
行为一致。