ASP.NET Core MVC — MVC执行概貌(2) ControllerActionInvoker与Filters管道

从实现上说,ControllerActionInvoker其实是ResourceInvoker的子类。其InvokeAsync()方法的主要流程就是调用InvokeFilterPipelineAsync()

ResourceInvoker

ResourceInvoker中的Resource含义和Resource filters中的含义相同。但是这里的ResourceInvoker会负责调用整个Filter管道,主要包括Authorization Filters(2.x)、Exception FiltersModel BindingAction Filters、及Result Filters的全部过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public virtual async Task InvokeAsync()
{
try{
//.. diagnose;

using (_logger.ActionScope(_actionContext.ActionDescriptor)){
// ... log
try {
await InvokeFilterPipelineAsync();
} finally{
ReleaseResources();
// ... log
}
}
} finally {
//.. diagnose;
}
}

显然,这里的InvokeFilterPipelineAsync()是整个方法的核心,该方法会不停地尝试调用自身的一个Next方法,直至结束:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 FiltersAction本身的调用,则交由抽象方法InvokeInnerFilterAsync()定义,延迟到子类中实现。

ASP.NET Core中内置的ResourceInvoker实现有ControllerActionInvokerPageActionInvoker,分别负责对MVCAction进行调用和对RazorPagehandler进行调用。

ControllerActionInvoker

ControllerActionInvoker对父类抽象方法InvokeInnerFilterAsync()的实现是也是通过状态机实现,如果是同步调用,大致的流程是:

  1. filter.OnActionExecuting(),
  2. InvokeActionMethodAsync()
  3. filter.OnActionExecuted()

事实上,ASP.NET Core MVC中内置的Controller抽象类自身也是一个IActionFilter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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)方法会按如下顺序依次调用:

  1. OnActionExecuting(executingContext)方法
  2. next()委托,也就是Action方法本身
  3. OnActionExecuted(executedContext)方法
    和普通的ActionFilter行为一致。