Обработка необработанных исключений (C#)
Просмотреть или скачать образец кода (описание загрузки)
Если ошибка среды выполнения возникает в веб-приложении в рабочей среде, важно уведомлять разработчика и регистрировать ошибку, чтобы она была диагностирована в последующий момент времени. В этом руководстве представлен обзор того, как ASP.NET обрабатывает ошибки среды выполнения и рассматривает один из способов выполнения пользовательского кода всякий раз, когда необработанные пузырьки исключений до среды выполнения ASP.NET.
Введение
Если необработанное исключение возникает в приложении ASP.NET, оно пузырька до среды выполнения ASP.NET, которая вызывает Error
событие и отображает соответствующую страницу ошибки. Существует три различных типа страниц ошибок: желтый экран ошибки среды выполнения (YSOD); YSOD сведений об исключении; и пользовательские страницы ошибок. В предыдущем руководстве мы настроили приложение для использования пользовательской страницы ошибок для удаленных пользователей и YSOD сведений об исключении для пользователей, посещающих локально.
Использование понятной пользовательской страницы ошибок, которая соответствует виду и чувству сайта, предпочтительна для YSOD по умолчанию, но отображение пользовательской страницы ошибок является лишь одной частью комплексного решения по обработке ошибок. При возникновении ошибки в рабочей среде важно, чтобы разработчики уведомляли об ошибке, чтобы они могли раскопить причину исключения и устранить ее. Кроме того, сведения об ошибке должны быть записаны в журнал, чтобы ошибка была проверена и диагностирована в более позднюю точку времени.
В этом руководстве показано, как получить доступ к подробным сведениям об необработанных исключениях, чтобы они могли быть зарегистрированы и уведомлены разработчиком. В двух руководствах, приведенных в этом руководстве, рассматриваются библиотеки ведения журнала ошибок, которые после немного конфигурации автоматически уведомляют разработчиков об ошибках среды выполнения и регистрируют их сведения.
Примечание.
Сведения, рассмотренные в этом руководстве, наиболее полезны, если необходимо обрабатывать необработанные исключения в определенном уникальном или настраиваемом режиме. В случаях, когда нужно регистрировать исключение и уведомлять разработчика, использование библиотеки ведения журнала ошибок — это способ перехода. В следующих двух руководствах представлен обзор двух таких библиотек.
Выполнение кода приError
вызове события
События предоставляют объект механизм для сигнала о том, что произошло что-то интересное, и для другого объекта для выполнения кода в ответ. Как ASP.NET разработчик вы привыкли думать с точки зрения событий. Если вы хотите запустить код, когда посетитель нажимает определенную кнопку, создайте обработчик событий для этого события Button Click
и поместите код туда. Учитывая, что среда выполнения ASP.NET вызывает событие Error
всякий раз, когда возникает необработанное исключение, следует, что код для ведения журнала сведений об ошибке будет проходить в обработчике событий. Но как создать обработчик событий для Error
события?
Это Error
событие является одним из многих событий классаHttpApplication
, которые создаются на определенных этапах конвейера HTTP во время существования запроса. Например, HttpApplication
событие класса BeginRequest
вызывается в начале каждого запроса. Его AuthenticateRequest
событие возникает, когда модуль безопасности определил запрашивающего объекта. Эти HttpApplication
события позволяют разработчику страницы выполнять пользовательскую логику в различных точках времени существования запроса.
Обработчики HttpApplication
событий для событий можно поместить в специальный файл с именем Global.asax
. Чтобы создать этот файл на веб-сайте, добавьте новый элемент в корень веб-сайта с помощью шаблона "Глобальный класс приложений" с именем Global.asax
.
Рис. 1. Добавление Global.asax
в веб-приложение
(Щелкните, чтобы просмотреть изображение полного размера)
Содержимое и структура файла, созданного Global.asax
Visual Studio, немного отличаются в зависимости от того, используется ли проект веб-приложения (WAP) или проект веб-сайта (WSP). С WAP Global.asax
реализуется как два отдельных файла — Global.asax
и Global.asax.cs
. Файл Global.asax
содержит ничего, кроме @Application
директивы, ссылающейся .cs
на файл; обработчики событий, интересующие вас, определены в Global.asax.cs
файле. Для WSPs создается только один файл, Global.asax
а обработчики событий определяются в блоке <script runat="server">
.
ФайлGlobal.asax
, созданный в WAP в шаблоне глобального класса приложений Visual Studio, включает обработчики событий с именем Application_BeginRequest
, Application_AuthenticateRequest
а также Application_Error
обработчики событий для HttpApplication
событий BeginRequest
AuthenticateRequest
и Error
соответственно. Существуют также обработчики событий с именем Application_Start
, Application_End
Session_Start
и Session_End
, которые являются обработчиками событий, которые запускаются при запуске веб-приложения, когда запускается новый сеанс, когда приложение заканчивается, и когда сеанс заканчивается соответственно. ФайлGlobal.asax
, созданный в WSP Visual Studio, содержит только Application_Error
обработчики событий , и Session_Start
Application_End
Session_End
, Application_Start
Примечание.
При развертывании приложения ASP.NET необходимо скопировать Global.asax
файл в рабочую среду. Файл Global.asax.cs
, созданный в WAP, не требуется копировать в рабочую среду, так как этот код компилируется в сборку проекта.
Обработчики событий, созданные шаблоном глобального класса приложений Visual Studio, не являются исчерпывающими. Можно добавить обработчик событий для любого HttpApplication
события, назвав обработчик Application_EventName
событий. Например, можно добавить следующий код Global.asax
в файл для создания обработчика событий для AuthorizeRequest
события:
protected void Application_AuthorizeRequest(object sender, EventArgs e)
{
// Event handler code
}
Аналогичным образом можно удалить любые обработчики событий, созданные шаблоном глобального класса приложений, которые не нужны. Для этого руководства требуется только обработчик событий для Error
события. Вы можете удалить другие обработчики событий из Global.asax
файла.
Примечание.
Модули HTTP предлагают другой способ определения обработчиков событий для HttpApplication
событий. Модули HTTP создаются в виде файла класса, который можно поместить непосредственно в проект веб-приложения или разделить на отдельную библиотеку классов. Так как они могут быть разделены в библиотеку классов, модули HTTP предлагают более гибкую и повторно использованную модель для создания HttpApplication
обработчиков событий. Global.asax
В то время как файл предназначен для веб-приложения, в котором он находится, модули HTTP можно скомпилировать в сборки, в то время как добавление модуля HTTP на веб-сайт так же просто, как удаление сборки в папке Bin
и регистрация модуля в Web.config
. В этом руководстве не рассматривается создание и использование модулей HTTP, но две библиотеки ведения журнала ошибок, используемые в следующих двух руководствах, реализуются как модули HTTP. Дополнительные сведения о преимуществах модулей HTTP см. в статье "Использование модулей HTTP и обработчиков для создания подключаемых ASP.NET компонентов".
Получение сведений об необработанных исключениях
На этом этапе у нас есть файл Global.asax с обработчиком Application_Error
событий. Когда этот обработчик событий выполняется, необходимо уведомить разработчика об ошибке и записать сведения о нем. Для выполнения этих задач сначала необходимо определить сведения об исключении, которое было создано. Используйте метод объекта GetLastError
Server для получения сведений об необработанных исключениях, которые привели Error
к возникновению события.
protected void Application_Error(object sender, EventArgs e)
{
// Get the error details
HttpException lastErrorWrapper =
Server.GetLastError() as HttpException;
}
Метод GetLastError
возвращает объект типаException
, который является базовым типом для всех исключений в платформа .NET Framework. Однако в приведенном выше коде выполняется приведение объекта Exception, возвращаемого GetLastError
HttpException
объектом. Error
Если событие запускается, так как исключение было создано во время обработки ресурса ASP.NET, то исключение, которое было создано, будет заключено в оболочкуHttpException
. Чтобы получить фактическое исключение, которое предопределено InnerException
событием Error, используйте свойство. Error
Если событие возникло из-за исключения на основе HTTP, например запроса на несуществующую страницу, HttpException
создается исключение, но не имеет внутреннего исключения.
Следующий код используется GetLastErrormessage
для получения сведений об исключении, которое вызвало Error
событие, сохраняя HttpException
переменную с именем lastErrorWrapper
. Затем он сохраняет трассировку типа, сообщения и стека исходного исключения в трех строковых переменных, проверяя, является ли lastErrorWrapper
фактическое исключение, которое активировало Error
событие (в случае исключений на основе HTTP) или если это просто оболочка для исключения, которое было создано при обработке запроса.
protected void Application_Error(object sender, EventArgs e)
{
// Get the error details
HttpException lastErrorWrapper =
Server.GetLastError() as HttpException;
Exception lastError = lastErrorWrapper;
if (lastErrorWrapper.InnerException != null)
lastError = lastErrorWrapper.InnerException;
string lastErrorTypeName = lastError.GetType().ToString();
string lastErrorMessage = lastError.Message;
string lastErrorStackTrace = lastError.StackTrace;
}
На этом этапе у вас есть все сведения, необходимые для написания кода, который будет записывать сведения об исключении в таблицу базы данных. Вы можете создать таблицу базы данных со столбцами для каждого интересующего вас типа, сообщения, трассировки стека и т. д., а также других полезных элементов информации, таких как URL-адрес запрошенной страницы и имя пользователя, вошедшего в систему. В обработчике Application_Error
событий необходимо подключиться к базе данных и вставить запись в таблицу. Аналогичным образом можно добавить код для оповещения разработчика об ошибке по электронной почте.
Библиотеки ведения журнала ошибок, рассмотренные в следующих двух руководствах, предоставляют такие функциональные возможности из поля, поэтому вам не нужно самостоятельно создавать это ведение журнала ошибок и уведомления. Тем не менее, чтобы продемонстрировать, что событие вызывается и что Error
Application_Error
обработчик событий можно использовать для регистрации сведений об ошибках и уведомления разработчика, давайте добавим код, который уведомляет разработчика о возникновении ошибки.
Уведомление разработчика о возникновении необработанного исключения
Если необработанное исключение возникает в рабочей среде, важно предупредить группу разработчиков, чтобы они могли оценить ошибку и определить, какие действия необходимо предпринять. Например, если при подключении к базе данных возникает ошибка, необходимо дважды проверить строка подключения и, возможно, открыть запрос в службу поддержки с вашей компанией веб-хостинга. Если исключение произошло из-за ошибки программирования, может потребоваться добавить дополнительный код или логику проверки, чтобы предотвратить такие ошибки в будущем.
Классы платформа .NET Framework в System.Net.Mail
пространстве имен упрощают отправку сообщения электронной почты. Класс MailMessage
представляет сообщение электронной почты и имеет такие свойства, как To
, From
, , Subject
Body
и Attachments
. Используется для отправки MailMessage
объекта с помощью указанного SMTP-сервера. Параметры SMTP-сервера можно задать программным или декларативным образом в элементе <system.net>
в элементеWeb.config file
.SmtpClass
Дополнительные сведения об отправке сообщений электронной почты в приложении ASP.NET см. в моей статье, отправке электронной почты с сайта веб-страницы ASP.NET и System.Net.Mail.
Примечание.
Элемент <system.net>
содержит параметры SMTP-сервера, используемые классом SmtpClient
при отправке сообщения электронной почты. У вашей компании веб-размещения, скорее всего, есть SMTP-сервер, который можно использовать для отправки электронной почты из приложения. Обратитесь к разделу поддержки веб-узла для получения сведений о параметрах SMTP-сервера, которые следует использовать в веб-приложении.
Добавьте следующий код в Application_Error
обработчик событий, чтобы отправить разработчику сообщение электронной почты при возникновении ошибки:
void Application_Error(object sender, EventArgs e)
{
// Get the error details
HttpException lastErrorWrapper =
Server.GetLastError() as HttpException;
Exception lastError = lastErrorWrapper;
if (lastErrorWrapper.InnerException != null)
lastError = lastErrorWrapper.InnerException;
string lastErrorTypeName = lastError.GetType().ToString();
string lastErrorMessage = lastError.Message;
string lastErrorStackTrace = lastError.StackTrace;
const string ToAddress = "support@example.com";
const string FromAddress = "support@example.com";
const string Subject = "An Error Has Occurred!";
// Create the MailMessage object
MailMessage mm = new MailMessage(FromAddress, ToAddress);
mm.Subject = Subject;
mm.IsBodyHtml = true;
mm.Priority = MailPriority.High;
mm.Body = string.Format(@"
<html>
<body>
<h1>An Error Has Occurred!</h1>
<table cellpadding=""5"" cellspacing=""0"" border=""1"">
<tr>
<tdtext-align: right;font-weight: bold"">URL:</td>
<td>{0}</td>
</tr>
<tr>
<tdtext-align: right;font-weight: bold"">User:</td>
<td>{1}</td>
</tr>
<tr>
<tdtext-align: right;font-weight: bold"">Exception Type:</td>
<td>{2}</td>
</tr>
<tr>
<tdtext-align: right;font-weight: bold"">Message:</td>
<td>{3}</td>
</tr>
<tr>
<tdtext-align: right;font-weight: bold"">Stack Trace:</td>
<td>{4}</td>
</tr>
</table>
</body>
</html>",
Request.RawUrl,
User.Identity.Name,
lastErrorTypeName,
lastErrorMessage,
lastErrorStackTrace.Replace(Environment.NewLine, "<br />"));
// Attach the Yellow Screen of Death for this error
string YSODmarkup = lastErrorWrapper.GetHtmlErrorMessage();
if (!string.IsNullOrEmpty(YSODmarkup))
{
Attachment YSOD =
Attachment.CreateAttachmentFromString(YSODmarkup, "YSOD.htm");
mm.Attachments.Add(YSOD);
}
// Send the email
SmtpClient smtp = new SmtpClient();
smtp.Send(mm);
}
Хотя приведенный выше код довольно длинен, основная часть этого кода создает HTML-код, который отображается в сообщении электронной почты, отправленном разработчику. Код начинается с ссылки на HttpException
возвращаемый методом GetLastError
(lastErrorWrapper
). Фактическое исключение, вызываемое запросом, извлекается через lastErrorWrapper.InnerException
переменную и назначается переменной lastError
. Сведения о типе, сообщении и трассировке стека извлекаются из lastError
трех строковых переменных.
MailMessage
Затем создается объект с именемmm
. Текст электронной почты отформатирован в формате HTML и отображает URL-адрес запрошенной страницы, имя пользователя, вошедшего в систему, и сведения об исключении (тип, сообщение и трассировка стека). Одним из холодных вещей класса HttpException
является создание HTML-кода, используемого для создания желтого экрана исключения (YSOD) путем вызова метода GetHtmlErrorMessage. Этот метод используется здесь для получения разметки YSOD сведений об исключении и добавления его в сообщение электронной почты в виде вложения. Одно слово предостережения: если исключение, вызвавшее Error
событие, было исключением на основе HTTP (например, запросом на несуществующую страницу), GetHtmlErrorMessage
метод вернет.null
Последний шаг — отправить MailMessage
. Это делается путем создания нового SmtpClient
метода и вызова его Send
метода.
Примечание.
Прежде чем использовать этот код в веб-приложении, необходимо изменить значения в ToAddress
константах FromAddress
на support@example.com любой адрес электронной почты, от которого следует отправлять и из которого отправляется уведомление об ошибке. Кроме того, необходимо указать параметры SMTP-сервера в <system.net>
разделе в Web.config
разделе. Обратитесь к поставщику веб-узла, чтобы определить используемые параметры SMTP-сервера.
При использовании этого кода в любое время разработчик отправляет сообщение электронной почты, включающее ошибку и включающее YSOD. В предыдущем руководстве мы продемонстрировали ошибку среды выполнения, посещая Genre.aspx и передавая недопустимое ID
значение через строку запросов, например Genre.aspx?ID=foo
. На странице с Global.asax
файлом на месте создается тот же интерфейс пользователя, что и в предыдущем руководстве. В среде разработки вы будете продолжать видеть желтый экран исключения, а в рабочей среде вы увидите пользовательскую страницу ошибок. В дополнение к этому существующему поведению разработчик отправляет сообщение электронной почты.
На рисунке 2 показана электронная почта, полученная при посещении Genre.aspx?ID=foo
. Текст сообщения электронной почты содержит сведения об исключении, а YSOD.htm
вложение отображает содержимое, отображаемое в YSOD сведений об исключении (см . рис. 3).
Рис. 2. Разработчик отправляет уведомление по электронной почте при возникновении необработанного исключения
(Щелкните, чтобы просмотреть изображение полного размера)
Рис. 3. Уведомление по электронной почте содержит сведения об исключении YSOD в виде вложения
(Щелкните, чтобы просмотреть изображение полного размера)
Как использовать пользовательскую страницу ошибок?
В этом руководстве показано, как использовать Global.asax
обработчик Application_Error
событий для выполнения кода при возникновении необработанного исключения. В частности, мы использовали этот обработчик событий для уведомления разработчика об ошибке; Мы могли бы расширить его, чтобы также регистрировать сведения об ошибке в базе данных. Наличие обработчика событий не влияет на работу конечного Application_Error
пользователя. Они по-прежнему видят настроенную страницу ошибок, будь то YSOD сведений об ошибке, YSOD или настраиваемая страница ошибок.
Естественно, Global.asax
что при использовании пользовательской страницы ошибок требуется файл и Application_Error
событие. Когда возникает ошибка, пользователь отображает пользовательскую страницу ошибок, поэтому почему мы не можем поместить код, чтобы уведомить разработчика и записать сведения об ошибке в класс кода за классом настраиваемой страницы ошибок? Хотя вы, безусловно, можете добавить код в класс кода пользовательской страницы ошибок, у вас нет доступа к сведениям об исключении, вызвавшее Error
событие при использовании метода, который мы изучили в предыдущем руководстве. Вызов метода из пользовательской GetLastError
страницы ошибок возвращается Nothing
.
Причина этого поведения заключается в том, что пользовательская страница ошибок достигается с помощью перенаправления. Когда необработанное исключение достигает среды выполнения ASP.NET, подсистема ASP.NET вызывает его Error
событие (который выполняет Application_Error
обработчик событий), а затем перенаправляет пользователя на пользовательскую страницу ошибок путем выдачи Response.Redirect(customErrorPageUrl)
. Метод Response.Redirect
отправляет клиенту ответ с кодом состояния HTTP 302, указав браузеру запрос нового URL-адреса, а именно настраиваемую страницу ошибок. Затем браузер автоматически запрашивает эту новую страницу. Вы можете сказать, что пользовательская страница ошибок была запрошена отдельно от страницы, в которой возникла ошибка, так как адресная строка браузера изменяется на URL-адрес настраиваемой страницы ошибок (см . рис. 4).
Рис. 4. При возникновении ошибки браузер перенаправляется по URL-адресу пользовательской страницы ошибок
(Щелкните, чтобы просмотреть изображение полного размера)
Чистый эффект заключается в том, что запрос, в котором произошло необработанное исключение, заканчивается, когда сервер отвечает на перенаправление HTTP 302. Последующий запрос на пользовательскую страницу ошибок — это новый запрос; По этому моменту подсистема ASP.NET отбрасывает сведения об ошибке и, более того, не имеет способа связать необработанное исключение в предыдущем запросе с новым запросом для настраиваемой страницы ошибок. GetLastError
Поэтому возвращается null
при вызове из пользовательской страницы ошибок.
Однако можно выполнить пользовательскую страницу ошибок во время того же запроса, вызвавшего ошибку. Метод Server.Transfer(url)
передает выполнение указанному URL-адресу и обрабатывает его в одном запросе. Код в обработчике событий можно переместить в Application_Error
класс кода пользовательской страницы ошибок, заменив его Global.asax
следующим кодом:
protected void Application_Error(object sender, EventArgs e)
{
// Transfer the user to the appropriate custom error page
HttpException lastErrorWrapper =
Server.GetLastError() as HttpException;
if (lastErrorWrapper.GetHttpCode() == 404)
{
Server.Transfer("~/ErrorPages/404.aspx");
}
else
{
Server.Transfer("~/ErrorPages/Oops.aspx");
}
}
Теперь, когда необработанное исключение возникает, Application_Error
обработчик событий передает управление соответствующей пользовательской страницей ошибок на основе кода состояния HTTP. Так как элемент управления был передан, пользовательская страница ошибок имеет доступ к необработанным сведениям об исключении с помощью Server.GetLastError
и может уведомить разработчика об ошибке и записать его сведения. Вызов Server.Transfer
останавливает обработчик ASP.NET перенаправлять пользователя на пользовательскую страницу ошибок. Вместо этого содержимое настраиваемой страницы ошибок возвращается в качестве ответа на страницу, которая вызвала ошибку.
Итоги
Если необработанное исключение возникает Error
в веб-приложении ASP.NET, среда выполнения ASP.NET вызывает событие и отображает настроенную страницу ошибки. Мы можем уведомить разработчика об ошибке, записать сведения или обработать его другим способом, создав обработчик событий для события Error. Существует два способа создания обработчика событий для HttpApplication
таких событий, как Error
в Global.asax
файле или в модуле HTTP. В этом руководстве показано, как создать Error
обработчик событий в Global.asax
файле, который уведомляет разработчиков об ошибке с помощью сообщения электронной почты.
Создание обработчика Error
событий полезно, если необходимо обрабатывать необработанные исключения в определенном уникальном или настраиваемом режиме. Однако создание собственного Error
обработчика событий для регистрации исключения или уведомления разработчика не является самым эффективным использованием времени, так как уже существуют бесплатные и простые в использовании библиотеки ведения журнала ошибок, которые могут быть настроены в течение нескольких минут. В следующих двух руководствах рассматриваются две такие библиотеки.
Счастливое программирование!
Дополнительные материалы
Дополнительные сведения о разделах, описанных в этом руководстве, см. в следующих ресурсах:
- ASP.NET Общие сведения о модулях HTTP и обработчиках HTTP
- Корректное реагирование на необработанные исключения — обработка необработанных исключений
HttpApplication
Класс и объект приложения ASP.NET- Обработчики HTTP и модули HTTP в ASP.NET
- Отправка электронной почты в ASP.NET
- Общие сведения о
Global.asax
файле - Использование модулей HTTP и обработчиков для создания подключаемых компонентов ASP.NET
- Работа с файлом ASP.NET
Global.asax
- Работа с
HttpApplication
экземплярами