Exception Handling Application Block, Exception-Handler ausgeführt in ASP.NET nicht nennen Antwort.Ende()
Verwenden .NET 3.5, ASP.NET Enterprise Library 4.1 Exception-Handling und Logging-Blöcke, ich schrieb ein eigener exception-handler für die Anzeige einer standard-Fehler-Seite wie folgt:
[ConfigurationElementType(typeof(CustomHandlerData))]
public class PageExceptionHandler : IExceptionHandler {
public PageExceptionHandler(NameValueCollection ignore) {
}
public Exception HandleException(Exception ex, Guid handlingInstanceID) {
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ContentEncoding = Encoding.UTF8;
response.ContentType = "text/html";
response.Write(BuildErrorPage(ex, handlingInstanceID));
response.Flush();
//response.End(); //SOMETIMES DOES NOT WORK
return ex;
}
}
Dies ist aufgerufen, die eine exception-handling-Politik, wie diese:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
<exceptionHandling>
<exceptionPolicies>
<add name="Top Level">
<exceptionTypes>
<add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction="None" name="Exception">
<exceptionHandlers>
<add logCategory="General" eventId="0" severity="Error" title="Application Error"
formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
priority="0" useDefaultLogger="false" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="Log Full Details" />
<add type="PageExceptionHandler, Test, Culture=neutral, PublicKeyToken=null"
name="Display Error Page" />
</exceptionHandlers>
</add>
</exceptionTypes>
</add>
</exceptionPolicies>
</exceptionHandling>
</configuration>
Alles funktioniert gut, außer, dass der Fehler Seite war Sie eingebaut in eine beliebige markup angezeigt wurde, die zum Zeitpunkt der Fehler aufgetreten ist. Ich dachte, dass das hinzufügen response.End()
in der exception-handler dieses problem lösen würde. Es Tat, aber ich habe dann beobachtet, dass, manchmal, ASP.NET wirft ein ThreadAbortException
während Sie versuchen, bis zum Ende der Antwort-stream. Dies ist der einzige Typ der Ausnahme, die nicht abgefangen und ignoriert. Grrr! Kann mir jemand sagen:
- Unter welchen Bedingungen ASP.NET würde werfen ein
ThreadAbortException
wenn Sie versuchen, um das Ende der Antwort-stream? - Gibt es eine sicherere alternative zu
response.End()
dass ich verwenden könnte? - Wenn nicht, gibt es eine Möglichkeit zu erkennen, ob der response-stream "end-Lage" vor dem Aufruf
response.End()
?
BEARBEITEN - Mehr Kontext
Design-Ziel für diesen code ist, um es so einfach wie möglich fügen Sie EHAB-Stil Fehlerbehandlung, um eine web-app. Ich habe eine benutzerdefinierte IHttpModule
, die Hinzugefügt werden müssen, um die web.config
- Datei. In das Modul Application_Error
event ruft es ExceptionPolicy.HandleException
. Die Ausnahmebehandlung Politik muss so konfiguriert sein, rufen Sie die PageExceptionHandler
Klasse wie oben beschrieben. Das gesamte Verfahren beinhaltet nur eine kleine Menge von XML-config, keine zusätzlichen Dateien, und keine zusätzlichen Zeilen code in der verwendeten web-app.
In der Tat, der code, wie es steht, scheint gut zu funktionieren. Allerdings, in manchen Situationen ist es wünschenswert, eine explizite catch-block in der web-app den code zum aufrufen der Ausnahmebehandlung Politik direkt. Diese Art von Szenario ist, was nicht richtig funktioniert. Ich möchte eine Lösung, die funktioniert unter allen möglichen Methoden aufrufen. Ich bekomme den Eindruck, dass es wäre viel einfacher, wenn die EHAB war nicht beteiligt, aber es ist leider durchgängig in allen unseren Kodex, und bietet so viele andere Vorteile, die ich würde es vorziehen, es zu halten in.
BEARBEITEN - Testergebnisse
Erstellt habe ich eine Testumgebung für die Ausübung des Kodex in sechs verschiedenen Möglichkeiten:
- Schreiben auf der aktuellen Seite
HttpResponse
direkt. - Aufbau eines exception-Objekts und den Aufruf
ExceptionPolicy.HandleException(ex, "Top Level")
direkt. - Wirft ein exception-Objekt, fangen, und ruft
ExceptionPolicy.HandleException(ex, "Top Level")
im catch-block. - Wirft ein exception-Objekt, und lassen Sie den
Page_Error
Ereignis nennenExceptionPolicy.HandleException(ex, "Top Level")
. - Wirft ein exception-Objekt, und lassen Sie den
Application_Error
Ereignis nennenExceptionPolicy.HandleException(ex, "Top Level")
. - Wirft ein exception-Objekt und ließ meine benutzerdefinierte
IHttpModule
Klasse aufrufenExceptionPolicy.HandleException(ex, "Top Level")
.
Test-Ergebnisse für jede Methode ohne code zu beenden, die Antwort nach dem schreiben der Fehlermeldung markup der Seite:
- Methoden 1, 2, 3 - Fehler-Seite markup in Kombination mit der test-Seite markup.
- Methoden 4, 5, 6 - Fehler-Seite markup ersetzt der test-Seite markup (gewünschte Ergebnis).
Test-Ergebnisse für jede Methode, wenn HttpContext.Current.ApplicationInstance.CompleteRequest
genannt wurde:
- Methoden 1, 2, 3 - Fehler-Seite markup in Kombination mit der test-Seite markup.
- Methoden 4, 5, 6 - Fehler-Seite markup ersetzt der test-Seite markup (gewünschte Ergebnis).
Test-Ergebnisse für jede Methode, wenn HttpContext.Current.Response.End
genannt wurde:
- Methoden 1, 5, 6 - Fehler-Seite markup ersetzt der test-Seite markup (gewünschte Ergebnis).
- Methoden 2, 3, 4 - Fehler-Seite markup ersetzt der test-Seite markup, aber der EHAB wirft einen
ExceptionHandlingException
zweimal.
Test-Ergebnisse für jede Methode, wenn HttpContext.Current.Response.End
genannt wurde, aber eingewickelt in ein try
... catch
block:
- Methoden 5, 6 - Fehler-Seite markup ersetzt der test-Seite markup (gewünschte Ergebnis).
- Methoden 1, 3, 4 - Fehler-Seite markup ersetzt der test-Seite markup, aber ASP.NET wirft ein
ThreadAbortException
welche gefangen und absorbiert durch den catch-block. - Methode 2 - Fehler-Seite markup ersetzt der test-Seite markup, aber ich bekomme
ThreadAbortException
und auch zweiExceptionHandlingException
s.
Es ist eine lächerliche Verhaltensweisen. 🙁
- Meine Entschuldigung für das verlassen dieser Frage unbeaufsichtigt so lange. Meine Arbeit ist so, dass ich nicht oft die chance bekommen, die Arbeit an diesem Ding. 🙁
Du musst angemeldet sein, um einen Kommentar abzugeben.
Haben Sie einen Blick auf ELMAH.
Es gibt viele Artikel und how-to ' s auf ELMAH, einfach die google-oder bing-für den es 🙂
Vorteile
+ Es speichert fast alles
+ E-Mail-Benachrichtigung
+ Remote viewing von Fehlern
Ich würde vorschlagen, zu verwenden, und redirect auf eine Standard-Fehler-Seite, als Ariel erwähnt.
Haben Sie einen Blick auf diese Microsoft-Erklärung. Sie sagt, es gilt zu ASP.Net 1.1, aber ich denke, es gilt noch in 2.0. Grundsätzlich sollten Sie rufen die
HttpContext.Current.ApplicationInstance.CompleteRequest
Methode statt.Auch, ich bin mir nicht sicher, warum Sie nicht fangen die
ThreadAbortException
- warum können Sie nicht etwas tun wieMein Ansatz zum Umgang mit ASP.net Ausnahmen war immer, es zu fangen, melden Sie es und dann umleiten auf eine generische Fehler-Seite mit einigen standard-Fehlermeldung (der end-user wird sich nicht um Ausnahmen oder stack traces).
Sie bereits angemeldet sind die Ausnahme in der Richtlinie, bevor Sie den handler so, vielleicht alle Sie tun müssen ist, eine Antwort Umleitung auf eine Fehler-Seite und bewegen Sie den BuildErrorPage Logik. Sie können übergeben, die handlingInstanceId in den querystring.
Versuchen Sie Application_Error in der Globalen.asax erfassen unhandle Ausnahmen von jeder Seite in Ihrer Anwendung.
Kann dies helfen: http://msdn.microsoft.com/en-us/library/cyayh29d.aspx
Speziell
"Ihre clean-up-code muss in die catch-Klausel oder der finally-Klausel, weil eine ThreadAbortException wird erneut ausgelöst, durch die das system am Ende des finally-Klausel, oder am Ende des catch-Klausel, wenn es keinen finally-Klausel.
Können Sie verhindern, dass das system erneute auslösen der exception durch Aufruf der Thread -..::.ResetAbort Methode. Allerdings sollten Sie dies nur tun, wenn Sie Ihren eigenen code verursacht den ThreadAbortException.
"
Beachten Sie, dass Antwort.Ende und Antwort.Umleiten kann werfen eine ThreadAbortException-unter bestimmten Bedingungen.
Nach einer Menge Tests, die ich gefunden habe, nur zwei Ansätze, die funktionieren ohne Fehler.
Lösung 1
Keine änderung der aktuellen Architektur überhaupt. Die Globale exception-handler schon läuft, wie gewünscht. Wenn eine explizite catch-block ist notwendig, im code aus irgendeinem Grund (z.B. zu Rendern Validierungs-Fehler, die auf einem Eingabe-Formular), dann werde ich sagen, die Entwickler nennen
Response.End
explizit, z.B.Lösung 2
Den Versuch aufgeben, überschreiben Sie die aktuelle response-stream und eine echte Umleitung auf eine Fehlerseite. Dies funktioniert mit allen sechs test-harness-Methoden. Das nächste problem war, einen Weg zu finden, dies zu tun erforderlich, dass die minimal mögliche änderungen der Konsum-Projekt und abstrahiert alle schmutzigen details.
Schritt 1 - Fügen Sie einen Platzhalter
ErrorPage.ashx
- Datei zum Projekt enthält nur einen Verweis auf einen standard-web-Seite-handler-Klasse und kein code-behind.Schritt 2 - Redirect zu diese Seite, in die
PageExceptionHandler
Klasse, mit einem session-key übergeben Sie alle erforderlichen Daten ein.Schritt 3 - Stellen Sie die
WebApplicationErrorPage
- Klasse, ein wirklich dumm, HTTP-handler, der nur schreibt, um den response-stream.Abschluss
Ich denke, ich werde stick mit Lösung 1, da es sich nicht um das hacken und änderung der bestehenden Architektur (Umsetzung der Lösung 2 für real wird sehr viel komplexer, als die code-snippets oben schlagen). Ich werde die Datei entfernt-Lösung 2 für den Einsatz an anderer Stelle möglich.