Wenn ein Benutzer eine Seite lädt, stellt er eine oder mehrere Ajax-Anforderungen, die auf ASP.NET Web API 2-Controller treffen. Wenn der Benutzer zu einer anderen Seite navigiert, bevor diese Ajax-Anforderungen abgeschlossen sind, werden die Anforderungen vom Browser abgebrochen. Unser ELMAH HttpModule protokolliert dann zwei Fehler für jede stornierte Anfrage:
Fehler 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()
Fehler 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)
Wenn ich mir den Stacktrace ansehe, sehe ich, dass die Ausnahme von hier ausgelöst wird: https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http.WebHost/HttpControllerHandler.cs# L413
Meine Frage ist: Wie kann ich mit diesen Ausnahmen umgehen und sie ignorieren?
Es scheint außerhalb des Benutzercodes zu liegen ...
Anmerkungen:
- Ich verwende die ASP.NET-Web-API 2
- Die Web-API-Endpunkte sind eine Mischung aus asynchronen und nicht asynchronen Methoden.
- Unabhängig davon, wo ich die Fehlerprotokollierung hinzufüge, kann ich die Ausnahme im Benutzercode nicht abfangen
- Global.asax
Applicaiton_Error
TaskScheduler.UnobservedTaskException
- ELMAH-Fehlerfilterung
void ErrorLog_Filtering
( https://code.google.com/p/elmah/wiki/ErrorFiltering )
- Global.asax
asp.net
iis
asp.net-web-api
task-parallel-library
async-await
Bates Westmoreland
quelle
quelle
Antworten:
Dies ist ein Fehler in ASP.NET Web API 2, und ich glaube leider nicht, dass es eine Problemumgehung gibt, die immer erfolgreich sein wird. Wir haben einen Fehler gemeldet , um ihn auf unserer Seite zu beheben.
Letztendlich besteht das Problem darin, dass wir in diesem Fall eine abgebrochene Aufgabe an ASP.NET zurückgeben und ASP.NET eine abgebrochene Aufgabe wie eine nicht behandelte Ausnahme behandelt (das Problem wird im Anwendungsereignisprotokoll protokolliert).
In der Zwischenzeit können Sie so etwas wie den folgenden Code ausprobieren. Es wird ein Nachrichtenhandler der obersten Ebene hinzugefügt, der den Inhalt entfernt, wenn das Stornierungs-Token ausgelöst wird. Wenn die Antwort keinen Inhalt hat, sollte der Fehler nicht ausgelöst werden. Es gibt immer noch eine kleine Möglichkeit, dass dies passiert, da der Client die Verbindung direkt trennen kann, nachdem der Nachrichtenhandler das Stornierungs-Token überprüft hat, aber bevor der übergeordnete Web-API-Code dieselbe Überprüfung durchführt. Aber ich denke, es wird in den meisten Fällen helfen.
David
quelle
SendAsync
(Sie können dies simulieren, indem SieF5
im Browser eine URL gedrückt halten, die Anfragen an Ihre API stellt. Ich habe dieses Problem auch gelöst Hinzufügen desif (cancellationToken.IsCancellationRequested)
Schecks über dem Aufruf vonSendAsync
. Jetzt werden die Ausnahmen nicht mehr angezeigt, wenn der Browser Anfragen schnell storniert.Bei der Implementierung eines Ausnahmeprotokolls für WebApi wird empfohlen, die
System.Web.Http.ExceptionHandling.ExceptionLogger
Klasse zu erweitern , anstatt einen ExceptionFilter zu erstellen. Die WebApi-Interna rufen die Protokollmethode von ExceptionLoggers für abgebrochene Anforderungen nicht auf (Ausnahmefilter erhalten sie jedoch). Dies ist beabsichtigt.quelle
Hier ist eine weitere Problemumgehung für dieses Problem. Fügen Sie einfach am Anfang der OWIN-Pipeline eine benutzerdefinierte OWIN-Middleware hinzu, die Folgendes abfängt
OperationCanceledException
:quelle
Sie können versuchen, das Standardverhalten bei der Behandlung von TPL-Aufgabenausnahmen zu ändern, indem Sie
web.config
:Dann haben Sie eine
static
Klasse (mit einemstatic
Konstruktor) in Ihrer Web-App, die damit umgehen würdeAppDomain.UnhandledException
.Es scheint jedoch, dass diese Ausnahme tatsächlich irgendwo in der ASP.NET-Web-API-Laufzeit behandelt wird , bevor Sie überhaupt die Möglichkeit haben, sie mit Ihrem Code zu behandeln.
In diesem Fall sollten Sie in der Lage sein, es als Ausnahme der ersten Chance abzufangen
AppDomain.CurrentDomain.FirstChanceException
. Hier erfahren Sie , wie . Ich verstehe, dass dies möglicherweise nicht das ist, wonach Sie suchen.quelle
FirstChanceException
? Haben Sie versucht, es mit einer statischen Klasse zu behandeln, die über HTTP-Anforderungen hinweg bestehen bleibt?AppDomain.UnhandledException
oderAppDomain.CurrentDomain.FirstChanceException
kann ich die Ausnahme überprüfen, aber nicht abfangen und ignorieren. Ich habe keine Möglichkeit gesehen, diese Ausnahmen als mit einem dieser Ansätze behandelt zu markieren. Korrigieren Sie mich, wenn ich falsch liege.Ich bekomme manchmal die gleichen 2 Ausnahmen in meiner Web API 2-Anwendung, aber ich kann sie mit der
Application_Error
Methode inGlobal.asax.cs
und unter Verwendung eines generischen Ausnahmefilters abfangen .Das Lustige ist jedoch, dass ich diese Ausnahmen lieber nicht abfange, weil ich immer alle nicht behandelten Ausnahmen protokolliere, die die Anwendung zum Absturz bringen können (diese beiden sind jedoch für mich irrelevant und scheinen anscheinend nicht oder zumindest nicht zum Absturz zu kommen es, aber ich kann mich irren). Ich vermute, dass diese Fehler aufgrund eines Ablaufs der Zeitüberschreitung oder einer expliziten Stornierung durch den Client auftreten, aber ich hätte erwartet, dass sie innerhalb des ASP.NET-Frameworks behandelt und nicht als nicht behandelte Ausnahmen außerhalb des ASP.NET-Frameworks weitergegeben werden.
quelle
WinHTTP
API und nicht über einen Browser ausgegeben .Ich habe ein bisschen mehr Details zu diesem Fehler gefunden. Es gibt zwei mögliche Ausnahmen, die auftreten können:
OperationCanceledException
TaskCanceledException
Der erste Fall tritt auf, wenn die Verbindung unterbrochen wird, während Ihr Code im Controller ausgeführt wird (oder möglicherweise auch ein Systemcode). Während die zweite passiert, wenn die Verbindung getrennt wird, während sich die Ausführung innerhalb eines Attributs befindet (z
AuthorizeAttribute
. B. ).Die bereitgestellte Problemumgehung hilft also, die erste Ausnahme teilweise zu mildern, und hilft nicht bei der zweiten. Im letzteren Fall
TaskCanceledException
tritt das während desbase.SendAsync
Aufrufs selbst auf, anstatt dass das Stornierungs-Token auf true gesetzt wird.Ich kann zwei Möglichkeiten sehen, diese zu lösen:
TaskCanceledException
dass wir ihn ignorieren und ihn protokollieren möchten.Der einzige Weg, wie ich herausgefunden habe, dass wir versuchen können, die falschen Ausnahmen zu lokalisieren, besteht darin, zu überprüfen, ob Stacktrace Asp.Net-Material enthält. Scheint allerdings nicht sehr robust zu sein.
PS So filtere ich diese Fehler heraus:
quelle
response
Variable innerhalb des Versuchs und geben sie außerhalb des Versuchs zurück. Das kann doch nicht funktionieren, oder? Auch wo verwenden Sie die IsAspNetBugException?Wir haben die gleiche Ausnahme erhalten. Wir haben versucht, die Problemumgehung von @ dmatson zu verwenden, aber wir haben immer noch eine Ausnahme erhalten. Wir haben uns bis vor kurzem damit befasst. Wir haben festgestellt, dass einige Windows-Protokolle mit alarmierender Geschwindigkeit wachsen.
Fehlerdateien in: C: \ Windows \ System32 \ LogFiles \ HTTPERR
Die meisten Fehler betrafen "Timer_ConnectionIdle". Ich suchte herum und es schien, dass die Verbindung trotz Beendigung des Web-API-Aufrufs noch zwei Minuten nach der ursprünglichen Verbindung bestehen blieb.
Ich dachte mir dann, wir sollten versuchen, die Verbindung in der Antwort zu schließen und zu sehen, was passiert.
Ich
response.Headers.ConnectionClose = true;
habe dem SendAsync MessageHandler hinzugefügt , und soweit ich weiß, schließen die Clients die Verbindungen, und das Problem tritt nicht mehr auf.Ich weiß, dass dies nicht die beste Lösung ist, aber es funktioniert in unserem Fall. Ich bin mir auch ziemlich sicher, dass Sie dies in Bezug auf die Leistung nicht tun möchten, wenn Ihre API mehrere Aufrufe von demselben Client hintereinander erhält.
quelle