【问题标题】:Performing a server-side call using async/await pattern (error: TaskCanceledException)使用 async/await 模式执行服务器端调用(错误:TaskCanceledException)
【发布时间】:2015-04-14 17:14:34
【问题描述】:

我正在使用技术 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,它使用类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 的响应时关闭页面。在这种情况下,我收到此错误:

消息:System.Threading.Tasks.TaskCanceledException:一个任务是 取消。在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 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() 在 System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext() — 从先前抛出异常的位置结束堆栈跟踪 — 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 在 System.Web.Http.Controllers.ExceptionFilterResult.d__0.MoveNext()

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

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

我的代码中是否有关于 async/await 模式的错误,或者它总是那个讨厌的错误?

非常感谢!

编辑:我尝试了我链接的 SO 帖子中给出的解决方法(使用 CancelledTaskBugWorkaroundMessageHandler 类),但我仍然收到 TaskCanceledException。

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

【问题讨论】:

  • 异常有什么问题?您的应用程序是否崩溃?我认为行为是正常的,因为当客户离开时为什么任务应该继续工作。
  • 我想知道异常是否正常,因为异常通常是错误的同义词。另外,我想知道我是否可以正确捕获它以避免服务器日志中每天有数百个。
  • 你从哪里得到这个异常?作为 HTTP 响应?还是在调试器中?
  • 我添加了一个答案,使我能够最终正确处理此异常。这也回答了你的问题。 :)

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


【解决方案1】:

我使用自己的 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.");
    }
}

Logger 类来自 Enterprise Library Application Blocks。

【讨论】:

  • 这是蜜蜂的膝盖,我遇到了 IExceptionHandler 在 Web API 2 中没有捕捉到 TaskCancelledException 的问题,这个例子解决了这个问题。非常感谢!
【解决方案2】:

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

【讨论】:

  • 好的,那么处理此类情况的最佳做法是什么?我没有在 Microsoft 的文档中阅读与该行为相关的任何内容。为了处理异常,我测试了问题中链接的 SO 帖子的解决方法,但我仍然遇到它。
  • 这个异常似乎来自MVC内部代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 2019-05-24
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
相关资源
最近更新 更多