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的全部过程:

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 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

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行为一致。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值