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

当用户加载一个页面时,它会发出一个或多个Ajax请求,这些请求会触发ASP.NET Web API 2控制器。 如果用户导航到另一个页面,则在完成这些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)

看着stacktrace,我看到这里抛出了异常:https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http.WebHost/HttpControllerHandler.cs# L413

我的问题是:我如何处理和忽略这些例外情况?

它似乎在用户代码之外...

笔记:

  • 我正在使用ASP.NET Web API 2
  • Web API端点是异步和非异步方法的混合体。
  • 无论我在哪里添加错误日志记录,我都无法捕捉用户代码中的异常
  • Global.asax Applicaiton_Error
  • TaskScheduler.UnobservedTaskException
  • ELMAH错误筛选void ErrorLog_Filtering (https://code.google.com/p/elmah/wiki/ErrorFiltering)

  • 这是ASP.NET Web API 2中的一个错误,不幸的是,我不认为有一种解决方法总是会成功的。 我们提出了一个错误来修复它。

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

    与此同时,您可以尝试下面的代码。 它添加了一个顶级消息处理程序,用于在取消令牌激发时删除内容。 如果响应没有内容,则不应触发该错误。 发生这种情况的可能性很小,因为客户端可能会在消息处理程序检查取消令牌后但在更高级别的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;
        }
    }
    

    在为WebApi实现异常记录器时,建议扩展System.Web.Http.ExceptionHandling.ExceptionLogger类而不是创建ExceptionFilter。 WebApi内部不会为已取消的请求调用ExceptionLoggers的Log方法(但是,异常过滤器将获得它们)。 这是设计。

    HttpConfiguration.Services.Add(typeof(IExceptionLogger), myWebApiExceptionLogger); 
    

    这是另一个解决此问题的解决方法。 只需在捕获OperationCanceledException的OWIN管道的开头添加一个自定义的OWIN中间件:

    #if !DEBUG
    app.Use(async (ctx, next) =>
    {
        try
        {
            await next();
        }
        catch (OperationCanceledException)
        {
        }
    });
    #endif
    
    链接地址: http://www.djcxy.com/p/20537.html

    上一篇: ASP.NET Web API OperationCanceledException when browser cancels the request

    下一篇: ASP.NET Web API Authentication