【问题标题】:await within OnActionExecutedAsync on ActionFilterAttribute在 ActionFilterAttribute 上的 OnActionExecutedAsync 中等待
【发布时间】:2017-12-18 20:35:31
【问题描述】:

我很难在 WebApi 项目中覆盖 ActionFilterAttributeOnActionExecutedAsync 方法。到目前为止,我有以下 c# 代码

public class MyFilter : ActionFilterAttribute
{
    public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionContext, CancellationToken cancellationToken)
    {
        var response = await MyAsyncMethod();
        if(response.SomeProperty)
            DoThing();
    }
}

但是在调试代码时,对 await 方法的响应永远不会返回。对于任何异步方法都是如此,因为我已经测试了一些我知道在我的代码库的其他地方工作的方法。我也尝试了 void 方法,以及使用 .Wait().Result 都有同样的问题。

var response = MyAsyncMethod().Result;
await MyVoidAsyncMethod();
MyVoidAsyncMethod().Wait(cancellationToken);

所以我认为问题在于等待 OnActionExecutedAsync 方法中的任何方法。

我注意到我可以毫无问题地等待基本方法。

await base.OnActionExecutedAsync(actionContext, cancellationToken);

如何在OnActionExecutedAsync 方法中调用异步方法?

更新示例显示纯粹等待的方法

由于通过确保等待链中的所有方法来建议 cmets 中的解决方案,我添加了一个示例,该示例仅显示仍然导致问题的等待方法。

public class MyFilter : ActionFilterAttribute
{
    public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionContext, CancellationToken cancellationToken)
    {
        await base.OnActionExecutedAsync(actionContext, cancellationToken);
        await DefinitelyAllAsync();
    }

    private async Task DefinitelyAllAsync()
    {
        var request = WebRequest.Create("http://www.stackoverflow.com");
        var response = await Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null) as HttpWebResponse;
        Debug.Assert(response?.StatusCode == HttpStatusCode.OK);
    }
}

这永远不会到达Debug.Assert

【问题讨论】:

  • 我在发布之前阅读了死锁问题,但我不清楚在这种情况下解决方案是什么
  • 不要阻塞,而是等待异步操作,就像答案告诉你的那样。
  • 但我在上面的示例中等待,这是我尝试的第一件事?
  • 不,你不是,你打电话给Result
  • 不,我的第一个例子是var response = await MyAsyncMethod();

标签: c# asynchronous asp.net-web-api2


【解决方案1】:

问题是在较早的时间点作用于请求的另一个过滤器没有正确处理异步。在下面的示例中,AuthFilter 将在其生命周期中比ActionFilter 更早地处理请求,如果它没有正确实现异步,那么当线程在请求​​中稍后遇到其他过滤器时,就会出现异步问题生命周期。我的错误是假设ActionFilter 在它自己的线程上运行,它是我的代码的入口点。以下代码显示了两个过滤器都正确实现了await 运算符。

Global.asax.cs

protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);
    GlobalConfiguration.Configuration.Filters.Add(new AuthFilter());
    GlobalConfiguration.Configuration.Filters.Add(new ActionFilter());
}

AuthFilter.cs

public class AuthFilter : IAuthorizationFilter
{
    public bool AllowMultiple => false;
    public async Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
    {
        // incorrect use of async in this Filter will break async in future filters
        return await continuation();
    }
}

ActionFilter.cs

public class ActionFilter : ActionFilterAttribute
{
    public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionContext, CancellationToken cancellationToken)
    {
        await base.OnActionExecutedAsync(actionContext, cancellationToken);
        await GetStackoverflow();
    }

    private async Task GetStackoverflow()
    {
        var request = WebRequest.Create("http://www.stackoverflow.com");
        var response = await Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null) as HttpWebResponse;
        // this debug is unreachable if a past filter has implemented async incorrectly
        Debug.Assert(response?.StatusCode == HttpStatusCode.OK);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-06
    • 2011-08-27
    • 2012-10-20
    • 2014-06-06
    • 2021-10-22
    相关资源
    最近更新 更多