Используя .NET 3.5, ASP.NET, Enterprise Library 4.1 Блоки обработки и регистрации исключений, я написал собственный обработчик исключений для отображения стандартной страницы ошибок, как показано ниже:
[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;
}
}
Это вызывается из политики обработки исключений:
<?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>
Все работает нормально, за исключением того, что страница ошибки была включена в разметку, отображаемую в момент возникновения ошибки. Я думал, что добавление response.End()
в обработчик исключений решит эту проблему. Это произошло, но затем я заметил, что иногда ASP.NET выдает ThreadAbortException
при попытке завершить поток ответа. Это единственный тип исключения, который не может быть перехвачен и проигнорирован. Хмм! Может кто-нибудь сказать мне:
- При каких условиях ASP.NET выдает
ThreadAbortException
при попытке завершить поток ответа?
- Есть ли более безопасная альтернатива
response.End()
, которую я мог бы использовать?
- Если нет, есть ли способ определить, является ли поток ответа "готовым к выполнению" перед вызовом
response.End()
?
РЕДАКТИРОВАТЬ - Больше контекста
Цель этого кода - максимально упростить добавление обработки ошибок в стиле EHAB в веб-приложение. У меня есть пользовательский IHttpModule
, который необходимо добавить в файл web.config
. В событии Application_Error
модуля он вызывает ExceptionPolicy.HandleException
. Политика обработки исключений должна быть настроена на вызов класса PageExceptionHandler
, описанного выше. Вся эта процедура включает в себя только небольшое количество XML-конфигурации, никаких дополнительных файлов и лишних строк кода в потребляющем веб-приложении.
На самом деле, код в его нынешнем виде работает нормально. Однако в некоторых ситуациях желательно иметь явный блок перехвата в коде веб-приложения, который напрямую вызывает политику обработки исключений. Этот сценарий - то, что не работает должным образом. Я хотел бы единственное решение, которое работает при всех возможных методах его вызова. У меня складывается впечатление, что было бы намного проще, если бы EHAB не использовался, но, к сожалению, он используется во всем нашем коде и обеспечивает так много других преимуществ, что я предпочел бы сохранить его.
EDIT - Результаты тестирования
Я создал тестовый комплект для проверки кода шестью различными способами:
- Запись на текущую страницу
HttpResponse
напрямую.
- Создание объекта исключения и прямой вызов
ExceptionPolicy.HandleException(ex, "Top Level")
.
- Бросок объекта исключения, его перехват и вызов
ExceptionPolicy.HandleException(ex, "Top Level")
в блоке catch.
- Создание объекта исключения и разрешение вызова события
Page_Error
ExceptionPolicy.HandleException(ex, "Top Level")
.
- Создание объекта исключения и разрешение вызова события
Application_Error
ExceptionPolicy.HandleException(ex, "Top Level")
.
- Бросок объекта исключения и разрешение моего пользовательского
IHttpModule
вызова класса ExceptionPolicy.HandleException(ex, "Top Level")
.
Результаты теста для каждого метода без кода для завершения ответа после записи разметки страницы с ошибкой:
- Методы 1, 2, 3 - разметка страницы с ошибкой в сочетании с разметкой тестовой страницы.
- Методы 4, 5, 6 - разметка страницы с ошибкой заменила разметку тестовой страницы (желаемый результат).
Результаты теста для каждого метода при вызове HttpContext.Current.ApplicationInstance.CompleteRequest
:
- Методы 1, 2, 3 - ошибка разметки страницы в сочетании с разметкой тестовой страницы.
- Методы 4, 5, 6 - разметка страницы с ошибкой заменила разметку тестовой страницы (желаемый результат).
Результаты теста для каждого метода при вызове HttpContext.Current.Response.End
:
- Методы 1, 5, 6 - разметка страницы с ошибкой заменила разметку тестовой страницы (желаемый результат).
- Методы 2, 3, 4 - разметка страницы ошибки заменила разметку тестовой страницы, но EHAB выдает
ExceptionHandlingException
дважды .
Результаты теста для каждого метода, когда был вызван HttpContext.Current.Response.End
, но заключены в блок try
... catch
:
- Методы 5, 6 - разметка страницы с ошибкой заменила разметку тестовой страницы (желаемый результат).
- Методы 1, 3, 4 - разметка страницы ошибки заменила разметку тестовой страницы, но ASP.NET выдает
ThreadAbortException
, который перехватывается и поглощается блоком перехвата. - Метод 2 - ошибка разметки страницы заменила разметку тестовой страницы, но я получаю
ThreadAbortException
, а также два ExceptionHandlingException
с.
Это смешной набор поведений. : - (