在ActionFilterAttribute上的OnActionExecutedAsync中等待

时间:2017-12-15 16:08:49

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

我无法覆盖WebApi项目中OnActionExecutedAsyncActionFilterAttribute方法。到目前为止,我有以下c#代码

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

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

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

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

我注意到我可以在没有问题的情况下等待基本方法。

await base.OnActionExecutedAsync(actionContext, cancellationToken);

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

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

作为评论中的一项决议,通过确保链中的所有方法都在等待,我添加了一个示例,仅显示仍在导致问题的等待方法。

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

1 个答案:

答案 0 :(得分:0)

问题是,在较早时刻对请求起作用的另一个过滤器未正确处理异步。在下面的示例中,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);
    }
}