Performing a server-side call using async/await pattern (error: TaskCanceledException)

Performing a server-side call using async/await pattern (error: TaskCanceledException)

我正在使用 WebAPI.

技术对我的 Web API 执行 AJAX 调用

处理该请求的方法如下:

[Route("RenderNotificationsPopup")]
[HttpGet]
public async Task<string> RenderNotificationsPopup(bool responsive = false)
{
    return await GetContentAsync(string.Format("RenderNotificationsPopup?responsive={0}", responsive ? 1 : 0));
}

此方法调用 GetContentAsync,它使用 class HttpClient.

执行服务器端调用
private async Task<string> GetContentAsync(string urlSuffix)
{
        using (var client = new HttpClient())
        {
            return await client.GetStringAsync(string.Format(
                "{0}/Header/{1}",
                ConfigurationManager.AppSettings["GatewaysHttpRoot"],
                urlSuffix));
        }
}

一切正常,除非用户在 AJAX 查询等待来自 WebApi 的响应时关闭页面。在那种情况下,我得到这个错误:

Message: System.Threading.Tasks.TaskCanceledException: A task was canceled. at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() — End of stack trace from previous location where exception was thrown — at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext() — End of stack trace from previous location where exception was thrown — at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at System.Web.Http.Controllers.ExceptionFilterResult.d__0.MoveNext()

我可以自己重现这个问题,方法是在我得到 AJAX 查询的响应之前加载页面并关闭它,就像在 WebApi 正在处理查询之前离开页面一样。

我在网上搜索了一下,发现有一个与此相关的错误(ASP.NET Web API OperationCanceledException when browser cancels the request)。尽管如此,它显然涉及旧版本的 WebApi 包,我正在使用最新版本。

我的代码中关于 async/await 模式的错误吗?还是它总是那个讨厌的错误?

非常感谢!

EDIT:我尝试了我链接的 SO post 中给出的解决方法(使用 class CancelledTaskBugWorkaroundMessageHandler),我仍然得到TaskCanceledException。

EDIT 2:看来这个问题无法避免。是否可以在 WebApi 应用程序中处理此类异常?

如果底层客户端连接已死,任务被取消是正常的。您需要处理异常。

我使用自己派生的 class of ExceptionFilterAttribute 来记录与 WebApi 应用程序相关的异常,覆盖方法 OnException.

我发现处理异常 TaskCanceledException 的正确方法是覆盖 OnExceptionAsync 而不是 OnException 并依赖于 属性 IsCancellationRequested 检测任务何时被取消。

这是我用作错误处理的方法:

public override async Task OnExceptionAsync(HttpActionExecutedContext context, CancellationToken cancellationToken)
{
    if (!cancellationToken.IsCancellationRequested)
    {
        //Handle domain specific exceptions here if any.

        //Handle all other Web Api (not all, but Web API specific only ) exceptions
        Logger.Write(context.Exception, "Email");

        context.Response = context.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "An unhandled exception was thrown.");
    }
}

其中 class Logger 来自企业库应用程序块。