ASP.NET Core中ActionFilterAttribute的Async OnActionExecuting是什么?

54

ASP.NET Core的ActionFilterAttribute有以下这些特性:

public virtual void OnActionExecuting(ActionExecutingContext context);
public virtual void OnActionExecuted(ActionExecutedContext context);
public virtual Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next);

我需要一个异步版本的OnActionExecuting,但是它并不存在。

然而我有一种感觉可以使用OnActionExecutionAsync替代它,因为它也有一个ActionExecutingContext参数。

我是否正确,尽管名称不同,它们在过程中触发的时间点相同?

另外,我需要对next参数做什么?在完成我的工作后,我只需要调用await next()吗?

就这些吗?我不确定,因为我找不到相关文档。

3个回答

111

异步过滤器的工作方式略有不同:首先执行必须在操作之前执行的代码,为实际逻辑调用 next(),最后添加将在操作之后执行的代码。

public async Task OnActionExecutionAsync(ActionExecutingContext context, 
                                         ActionExecutionDelegate next)
{

    // logic before action goes here

    await next(); // the actual action

    // logic after the action goes here
}

文档在这里:https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters#implementation


实际上,它在这里:https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters#implementation 的第二个代码块中。 - grokky
1
@grokky 基本实现会检查参数并调用另外两个方法。如果你不需要重写这两个方法,就不需要调用它。 - juunas
@grokky 你可以在这里查看源代码:https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Core/Filters/ActionFilterAttribute.cs - juunas
对于那些想知道委托是否抛出异常的人,请从 var result = await next(); 中获取结果,然后检查 result.Exception - jsgoupil

4
异步过滤器总是优先于同步过滤器实现。

根据 文档

  • 建议只实现同步或异步版本的过滤器接口,不要同时实现。运行时首先检查过滤器是否实现了异步接口,如果实现了,则调用该接口。如果没有,则调用同步接口的方法。如果在一个类中实现了异步和同步接口,仅调用异步方法。

但是您可以同时管理两者。例如:

public class TimestampFilter : IActionFilter, IAsyncActionFilter 
{    
    public void OnActionExecuting(ActionExecutingContext context)    
    {         
        context.ActionDescriptor.RouteValues["timestamp"] = DateTime.Now.ToString();    
    }

    public void OnActionExecuted(ActionExecutedContext context)    
    {         
        var ts = DateTime.Parse(context.ActionDescriptor. RouteValues["timestamp"]).AddHours(1).ToString();        
        context.HttpContext.Response.Headers["X-EXPIRY-TIMESTAMP"] = ts;    
    }

     public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)    
    {        
        this.OnActionExecuting(context);        
        var resultContext = await next();
        this.OnActionExecuted(resultContext);    
    }
 }


2
一个更好的模式:
public override async Task OnActionExecutionAsync(
    ActionExecutingContext context, 
    ActionExecutionDelegate next)
{
    try
    {
          //do your async things here                 
    }
    finally
    {
        await base.OnActionExecutionAsync(context, next); <--- notice this!
    }
}

1
这会导致每个请求多次调用操作。请勿使用此方法。 - Adam K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接