Using .NET 3.5, ASP.NET, Corporate Library 4.1. Blocking exceptions and logging, I wrote a special exception handler to display the standard error page as follows:
[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();
This is called from an exception handling policy, like this:
<?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>
Everything works fine, except that the error page was included in any markup displayed at the time the error occurred. I thought adding response.End() to the exception handler would solve this problem. This happened, but I noticed that sometimes ASP.NET throws a ThreadAbortException when trying to terminate the response flow. This is the only type of exception that cannot be caught and ignored. Hmm! Can anyone tell me:
- Under what conditions will ASP.NET throw a
ThreadAbortException when trying to terminate a response flow? - Is there a safer alternative to
response.End() that I could use? - If not, is there a way to determine if the response stream is βcompleteβ before calling
response.End() ?
EDIT - More Context
The goal of the project for this code is to make it as simple as possible to add EHAB-style error handling to a web application. I have a custom IHttpModule that needs to be added to the web.config . In the Application_Error module event, it throws an ExceptionPolicy.HandleException . An exception handling policy must be configured to call the PageExceptionHandler class described above. This entire procedure includes only a small number of XML configurations, additional files, and additional lines of code in a consuming web application.
In fact, code like it seems to be working fine. However, in some situations, it is desirable to have an explicit catch block in the web application code that invokes the exception handling policy directly. Such a scenario is something that does not work properly. I would like one solution to work under all possible ways of calling it. I get the impression that it would be much easier if EHAB were not involved, but, unfortunately, it is used throughout our code and provides so many other benefits that I would prefer to keep.
EDIT - test results
I created a test harness to implement the code in different ways:
- Direct write to the current
HttpResponse page. - Building an exception object and calling
ExceptionPolicy.HandleException(ex, "Top Level") directly. - Throwing an exception object, catching it, and calling
ExceptionPolicy.HandleException(ex, "Top Level") in the catch block. - Throwing an exception object and
Page_Error event ExceptionPolicy.HandleException(ex, "Top Level") . - Throwing an exception object and throwing
Application_Error on the ExceptionPolicy.HandleException(ex, "Top Level") event ExceptionPolicy.HandleException(ex, "Top Level") . - Throwing an exception object and calling my custom call
IHttpModule ExceptionPolicy.HandleException(ex, "Top Level") .
Test results for each method without code to complete the response after recording the markup of the error page:
- Methods 1, 2, 3 - The layout of the error page in combination with the layout of the test page.
- Methods 4, 5, 6 - The layout of the error page replaced the layout of the test page (desired result).
Test results for each method when HttpContext.Current.ApplicationInstance.CompleteRequest was called:
- Methods 1, 2, 3 - The layout of the error page in combination with the layout of the test page.
- Methods 4, 5, 6 - The layout of the error page replaced the layout of the test page (desired result).
Test results for each method when HttpContext.Current.Response.End was called:
- Methods 1, 5, 6 - The layout of the error page has replaced the layout of the test page (desired result).
- Methods 2, 3, 4 - Error page markup replaced test page markup, but EHAB throws an
ExceptionHandlingException twice.
Test results for each method when HttpContext.Current.Response.End was called, but wrapped in a try ... catch :
- Methods 5, 6 - The layout of the error page replaced the layout of the test page (desired result).
- Methods 1, 3, 4 - The error page markup replaced the test page markup, but ASP.NET throws a
ThreadAbortException that is caught and consumed by the catch block. - Method 2 - The error page markup replaced the test page markup, but I get a
ThreadAbortException , as well as two ExceptionHandlingException s.
This is a funny set of behaviors. :-(