异步WebApi ActionFilterAttribute。当异步操作仍在等待时,异步模块或处理程序已完成。

11

我理解await会等待一个任务(可等待对象)完成,但实际上这是什么意思我有点糊涂。

不起作用的代码:

public async override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
    if (actionExecutedContext.Response.Content != null)
    {
        var responseContent = await actionExecutedContext.Response.Content.ReadAsStringAsync();
        DoSomething(responseContent);
    }
}

能够正常工作的代码:does

public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
    if (actionExecutedContext.Response.Content != null)
    {
        var responseContent = actionExecutedContext.Response.Content.ReadAsStringAsync().ContinueWith(
        task =>
        {
            DoSomething(task.Result);
        });
    }
}

显然,错误信息An asynchronous module or handler completed while an asynchronous operation was still pending.告诉我,没有等待异步调用完成,而是"主"线程继续执行。我期望该线程会继续执行,但不是在当前方法内。我认为该线程将返回到asp.net堆栈中进行其他工作,并在await asyncOperation()操作完成后返回。

我在其他地方也使用了 await(例如等待 Web 服务响应),但在任何地方都没有遇到类似的问题。我想知道为什么 IActionFilterAttribute 的行为不同。实际上,我的 Web 服务调用可能比读取响应内容到字符串中需要更长的时间。

有人可以说明一下吗?我觉得我可能没有理解这个概念。


动作过滤器(MVC的一部分,而不是WebAPI)不支持异步操作。如果您需要异步操作过滤器,请尝试使用消息处理程序。哦,还有在这里投票 - Stephen Cleary
这是一个关于WebAPI的问题,我正在使用正确的ActionFilterAttribute(System.Web.Http...) - 你是在说它应该工作吗? :) - lapsus
我明白了。在这种情况下,您可能需要定义自己的 AsyncActionFilterAttribute 并实现 IActionFilter.ExecuteActionFilterAsync - Stephen Cleary
2个回答

13

将异步代码添加到返回void的方法中是危险的,并且几乎永远不是您实际想要做的。请参见返回void和返回Task之间的区别是什么?

相反,您需要重写/实现返回任务的方法。在这种情况下,ActionFilterAttribute隐藏了IHttpActionFilter提供的Task,因此您需要实现IActionFilter(ExecuteActionFilterAsync)而不是继承ActionFilterAttribute。如果您想将代码用作属性,请确保还从Attribute类派生。

例如:

public class AsyncActionFilterAttribute : Attribute, IActionFilter
{
    public async Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
    {
        HttpResponseMessage response = await continuation();
        DoSomething(response);
        return response;
    }
}

7

不要只是实现

public async override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)

你需要按照以下方式实现OnActionExecuted方法的异步版本:
public override Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)

使用这种方式,您可以在方法内部使用await,并且行为将与您期望的相同。

希望这能帮到您。


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