129 votes

ASP.NET l'API Web OperationCanceledException lorsque le navigateur annule la demande

Lorsqu'un utilisateur charge une page, il fait un ou plusieurs requêtes ajax, qui a frappé ASP.NET Web API 2 contrôleurs. Si l'utilisateur accède à une autre page, avant ces requêtes ajax complet, la demande est annulée par le navigateur. Notre ELMAH HttpModule puis deux journaux d'erreurs pour chaque annulé, à la demande:

Erreur 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()

Erreur 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)

En regardant la stacktrace, je vois que l'exception est levée à partir d'ici: https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http.WebHost/HttpControllerHandler.cs#L413

Ma question est: Comment puis-je gérer et d'ignorer ces exceptions?

Il semble être à l'extérieur de code d'utilisateur...

Notes:

  • Je suis à l'aide de ASP.NET Web API 2
  • L'API Web points sont un mélange de async et non de méthodes asynchrones.
  • Peu importe où je ajouter de la journalisation des erreurs, je suis incapable de rattraper l'exception dans le code de l'utilisateur

80voto

dmatson Points 1435

C'est un bug dans ASP.NET Web API 2 et malheureusement, je ne pense pas qu'il y a une solution de contournement qui est toujours une réussite. Nous avons déposé un bug à fixer sur notre côté.

En fin de compte, le problème est que nous revenons de l'annulation de la tâche à ASP.NET dans ce cas, et ASP.NET traite de l'annulation de la tâche comme une exception non gérée (il enregistre le problème dans le journal des événements d'Application).

En attendant, vous pouvez essayer quelque chose comme le code ci-dessous. Il ajoute un niveau supérieur gestionnaire de message supprime le contenu lorsque le jeton d'annulation des incendies. Si la réponse n'a pas de contenu, le bug ne devrait pas être déclenché. Il y a encore une petite chance qu'il pourrait se produire, parce que le client pourrait déconnecter juste après le message de gestionnaire vérifie que le jeton d'annulation, mais devant le haut-niveau de l'API Web code fait la même case. Mais je pense que ça va aider dans la plupart des cas.

David

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;
    }
}

3voto

Noseratio Points 23840

Vous pouvez essayer de changer le TPL par défaut de la tâche comportement de gestion des exceptions par web.config:

<configuration> 
    <runtime> 
        <ThrowUnobservedTaskExceptions enabled="true"/> 
    </runtime> 
</configuration>

Alors un static (avec un static constructeur) dans votre application web, qui serait en mesure de gérer AppDomain.UnhandledException.

Cependant, il semble que cette exception est réellement traitée quelque part à l'intérieur de ASP.NET Web API runtime, avant même d'avoir une chance de traiter avec votre code.

Dans ce cas, vous devriez être en mesure de l'attraper, comme une 1ère chance d'exception, avec AppDomain.CurrentDomain.FirstChanceException, voici comment. Je comprends que cela peut ne pas être ce que vous cherchez.

2voto

Gabriel S. Points 310

Parfois, j'ai les 2 mêmes exceptions dans mon Web API 2 de la demande, cependant, je peux les attraper avec l' Application_Error méthode de Global.asax.cs et à l'aide d'un générique filtre d'exception.

Le plus drôle, c'est bien, je préfère ne pas attraper ces exceptions, parce que j'ai toujours un journal de toutes les exceptions non gérées qui peut le plantage de l'application (ces 2, cependant, ne sont pas pertinentes pour moi et ne semblent pas ou au moins ne tombe pas en panne, mais j'ai peut-être mal). Je soupçonne que ces erreurs se montrer à cause de certaines délai d'expiration ou d'annulation explicite de la part du client, mais je me serais attendu à être traités à l'intérieur de la ASP.NET cadre et pas propagé à l'extérieur des exceptions non gérées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X