浏览器取消请求时出现 ASP.NET Web API OperationCanceledException

标签 asp.net iis asp.net-web-api task-parallel-library async-await

当用户加载页面时,它会发出一个或多个 ajax 请求,这些请求会命中 ASP.NET Web API 2 Controller 。如果用户导航到另一个页面,在这些 ajax 请求完成之前,浏览器会取消这些请求。然后,我们的 ELMAH HttpModule 会为每个取消的请求记录两个错误:

错误1:

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.TaskAwaiter`1.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.TaskAwaiter`1.GetResult()
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>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.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>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.<ExecuteAsync>d__0.MoveNext()

错误2:

System.OperationCanceledException: The operation was canceled.
   at System.Threading.CancellationToken.ThrowIfCancellationRequested()
   at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.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.Web.Http.WebHost.HttpControllerHandler.<CopyResponseAsync>d__7.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.Web.Http.WebHost.HttpControllerHandler.<ProcessRequestAsyncCore>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.Web.TaskAsyncHelper.EndTask(IAsyncResult ar)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

查看堆栈跟踪,我发现异常是从这里抛出的:https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http.WebHost/HttpControllerHandler.cs#L413

我的问题是:如何处理和忽略这些异常?

它似乎超出了用户代码...

注释:

  • 我正在使用 ASP.NET Web API 2
  • Web API 端点是异步和非异步方法的混合体。
  • 无论我在哪里添加错误日志记录,我都无法捕获用户代码中的异常

最佳答案

这是 ASP.NET Web API 2 中的一个错误,不幸的是,我认为没有一种解决方法总是能成功。我们提交了bug在我们这边修复它。

最终,问题在于我们在这种情况下将取消的任务返回给 ASP.NET,而 ASP.NET 将取消的任务视为未处理的异常(它将问题记录在应用程序事件日志中)。

同时,您可以尝试类似下面的代码。它添加了一个顶级消息处理程序,该处理程序在取消 token 触发时删除内容。如果响应没有内容,则不应触发该错误。发生这种情况的可能性仍然很小,因为客户端可能会在消息处理程序检查取消 token 之后但在更高级别的 Web API 代码执行相同检查之前立即断开连接。但我认为这在大多数情况下都会有帮助。

大卫

config.MessageHandlers.Add(new CancelledTaskBugWorkaroundMessageHandler());

class CancelledTaskBugWorkaroundMessageHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

        // Try to suppress response content when the cancellation token has fired; ASP.NET will log to the Application event log if there's content in this case.
        if (cancellationToken.IsCancellationRequested)
        {
            return new HttpResponseMessage(HttpStatusCode.InternalServerError);
        }

        return response;
    }
}

关于浏览器取消请求时出现 ASP.NET Web API OperationCanceledException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22157596/

相关文章:

tomcat - 使 Tomcat 9 忽略 Http 基本信息

.net - 在高负载的 .ashx http 处理程序中将记录附加到磁盘文件的最快、最安全的方法是什么?

c# - 如何在 web api 中发送两个对象作为响应消息和响应代码

c# - ASP.NET MVC : Is UpdateModel an "expensive" operation (due to Reflection)?

c# - 单击按钮时 JavaScript 警报出现问题

asp.net - 在预编译的部署网站中添加附属程序集

iis - 使用 IIS 将子目录的 URL 重写到不同的域

asp.net-core - Asp.Net Core 5 API Web 以 WCF 等流模式上传大文件

c# - 无法将类型为 'Newtonsoft.Json.Linq.JObject' 的对象转换为类型 'Newtonsoft.Json.Linq.JArray'

asp.net mvc [handleerror] [authorize] 与 JsonResult?