Обработка необработанных исключений (VB)

Скотт Митчелл

Просмотреть или скачать образец кода (как скачивать)

При возникновении ошибки среды выполнения в веб-приложении в рабочей среде важно уведомить разработчика и записать ее в журнал, чтобы ее можно было диагностировать позже. В этом руководстве представлен обзор того, как ASP.NET обрабатывает ошибки среды выполнения, и рассматривается один из способов выполнения пользовательского кода при каждом необработанных исключениях до среды выполнения ASP.NET.

Введение

При возникновении необработанного исключения в ASP.NET приложении оно выполняется в ASP.NET среде выполнения, которая вызывает Error событие и отображает соответствующую страницу ошибки. Существует три различных типа страниц ошибок: желтый экран смерти ошибки времени выполнения (YSOD); сведения об исключении YSOD; и пользовательские страницы ошибок. В предыдущем руководстве мы настроили приложение для использования настраиваемой страницы ошибок для удаленных пользователей и YSOD сведений об исключении для пользователей, посещающих локально.

Использование удобной для пользователя пользовательской страницы ошибок, которая соответствует интерфейсу сайта, предпочтительнее, чем YSOD ошибки среды выполнения по умолчанию, но отображение настраиваемой страницы ошибок является лишь одной из частей комплексного решения для обработки ошибок. При возникновении ошибки в приложении в рабочей среде важно, чтобы разработчики были уведомлены об этой ошибке, чтобы они могли узнать причину исключения и устранить ее. Кроме того, сведения об ошибке должны быть записаны в журнал, чтобы ее можно было проверить и диагностировать позже.

В этом руководстве показано, как получить доступ к сведениям о необработанных исключениях, чтобы их можно было заносить в журнал и уведомлять разработчика. В двух следующих руководствах рассматриваются библиотеки ведения журнала ошибок, которые после некоторой настройки автоматически уведомляют разработчиков об ошибках среды выполнения и регистрируют их сведения.

Примечание

Сведения, рассмотренные в этом руководстве, наиболее полезны, если вам нужно обрабатывать необработанных исключений каким-то уникальным или настраиваемым способом. В тех случаях, когда необходимо только записать исключение и уведомить разработчика, следует использовать библиотеку ведения журнала ошибок. В следующих двух учебниках представлен обзор двух таких библиотек.

Выполнение кода при возникновенииErrorсобытия

События предоставляют объекту механизм для сигнализации о том, что произошло что-то интересное, и для другого объекта для выполнения кода в ответ. Как разработчик ASP.NET вы привыкли думать с точки зрения событий. Если вы хотите запустить код, когда посетитель нажимает определенную кнопку, создайте обработчик событий для события этой кнопки Click и поместите в нее свой код. Учитывая, что среда выполнения ASP.NET вызывает свое Error событие всякий раз, когда возникает необработанное исключение, код для ведения журнала сведений об ошибке будет идти в обработчике событий. Но как создать обработчик событий для Error события?

Событие Error является одним из многих событий в HttpApplication классе , которые вызываются на определенных этапах конвейера HTTP в течение времени существования запроса. Например, HttpApplication событие класса BeginRequest возникает в начале каждого запроса; его AuthenticateRequest событие возникает, когда модуль безопасности идентифицирует инициатор запроса. Эти HttpApplication события предоставляют разработчику страницы средства для выполнения пользовательской логики в различные моменты времени существования запроса.

Обработчики HttpApplication событий можно поместить в специальный файл с именем Global.asax. Чтобы создать этот файл на веб-сайте, добавьте новый элемент в корень веб-сайта с помощью шаблона Global Application Class с именем Global.asax.

Снимок экрана: добавление нового элемента в корень веб-сайта с помощью шаблона

Рис. 1. Добавление Global.asax в веб-приложение
(Щелкните для просмотра полноразмерного изображения)

Содержимое и структура файла, Global.asax созданного Visual Studio, немного различаются в зависимости от того, используете ли вы проект веб-приложения (WAP) или проект веб-сайта (WSP). При использовании WAP Global.asax реализуется как два отдельных файла : Global.asax и Global.asax.vb. Файл Global.asax не содержит ничего, @Application кроме директивы, которая ссылается на .vb файл; обработчики событий, представляющие интерес, определяются в Global.asax.vb файле . Для WSP создается только один файл , Global.asaxа обработчики событий определяются в блоке <script runat="server"> .

Файл Global.asax , созданный в WAP шаблоном глобального класса приложения Visual Studio, включает обработчики событий с именами Application_BeginRequest, Application_AuthenticateRequestи Application_Error, которые являются обработчиками HttpApplication событий BeginRequest, AuthenticateRequestи Errorсоответственно. Существуют также обработчики событий с именами Application_Start, Session_Start, Application_Endи Session_End, которые являются обработчиками событий, которые срабатся при запуске веб-приложения, при запуске нового сеанса, при завершении приложения и при завершении сеанса соответственно. Файл Global.asax , созданный в WSP Visual Studio, содержит только обработчики Application_Errorсобытий , Application_Start, Session_Start, Application_Endи Session_End .

Примечание

При развертывании приложения ASP.NET необходимо скопировать файл в Global.asax рабочую среду. Файл Global.asax.vb , созданный в WAP, не требуется копировать в рабочую среду, так как этот код компилируется в сборку проекта.

Обработчики событий, созданные шаблоном глобального класса приложения Visual Studio, не являются исчерпывающими. Вы можете добавить обработчик событий для любого HttpApplication события, назвав обработчик Application_EventNameсобытий . Например, можно добавить следующий код в Global.asax файл, чтобы создать обработчик событий для AuthorizeRequest события:

Sub Application_AuthorizeRequest(ByVal sender As Object, ByVal e As EventArgs)
    ' Event handler code
End Sub

Аналогичным образом можно удалить любые обработчики событий, созданные шаблоном глобального класса приложения, которые не нужны. В этом руководстве требуется только обработчик событий для 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 событие.

Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
    ' Get the error details
    Dim lastErrorWrapper As HttpException = _
        CType(Server.GetLastError(), HttpException)
End Sub

Метод GetLastError возвращает объект типа Exception, который является базовым типом для всех исключений в платформа .NET Framework. Однако в приведенном выше коде объект Exception, возвращенный GetLastError , приводится к объекту HttpException . Error Если событие вызывается из-за исключения во время обработки ресурса ASP.NET, то созданное исключение помещается в HttpException. Чтобы получить фактическое исключение, которое ускорит событие Error, используйте InnerException свойство . Error Если событие возникло из-за исключения на основе HTTP, например запроса несуществующей страницы, HttpException создается исключение , но внутреннее исключение отсутствует.

В следующем коде GetLastErrormessage используется для получения сведений об исключении, которое активировало Error событие, сохраняя HttpException в переменной с именем lastErrorWrapper. Затем он сохраняет тип, сообщение и трассировку стека исходного исключения в трех строковых переменных, проверяя, является ли lastErrorWrapper фактическим исключением, вызвавшее Error событие (в случае исключений на основе HTTP), или является ли это просто оболочкой для исключения, которое было создано при обработке запроса.

Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
    ' Get the error details
    Dim lastErrorWrapper As HttpException = _
        CType(Server.GetLastError(), HttpException)

    Dim lastError As Exception = lastErrorWrapper
    If lastErrorWrapper.InnerException IsNot Nothing Then
        lastError = lastErrorWrapper.InnerException
    End If

    Dim lastErrorTypeName As String = lastError.GetType().ToString()
    Dim lastErrorMessage As String = lastError.Message
    Dim lastErrorStackTrace As String = lastError.StackTrace
End Sub

На этом этапе у вас есть все сведения, необходимые для написания кода, который будет записывать сведения об исключении в таблицу базы данных. Вы можете создать таблицу базы данных со столбцами для каждой из интересующих ошибок ( тип, сообщение, трассировка стека и т. д.), а также другие полезные сведения, такие как URL-адрес запрошенной страницы и имя пользователя, вошедшего в систему. Затем в обработчике Application_Error событий необходимо подключиться к базе данных и вставить запись в таблицу. Аналогичным образом можно добавить код для оповещения разработчика об ошибке по электронной почте.

Библиотеки ведения журнала ошибок, рассмотренные в следующих двух руководствах, предоставляют такие функциональные возможности, поэтому нет необходимости создавать эти ведения журнала ошибок и уведомления самостоятельно. Однако, чтобы продемонстрировать, что Error возникает событие и что Application_Error обработчик событий можно использовать для регистрации сведений об ошибке и уведомления разработчика, давайте добавим код, который уведомляет разработчика о возникновении ошибки.

Уведомление разработчика при возникновении необработанного исключения

При возникновении необработанного исключения в рабочей среде важно предупредить группу разработчиков, чтобы они могли оценить ошибку и определить, какие действия необходимо предпринять. Например, если при подключении к базе данных возникает ошибка, вам потребуется удвоить проверка строка подключения и, возможно, отправить запрос в службу поддержки в вашей компании по размещению веб-сайтов. Если исключение возникло из-за ошибки программирования, может потребоваться добавить дополнительный код или логику проверки, чтобы предотвратить такие ошибки в будущем.

Классы платформа .NET Framework в System.Net.Mail пространстве имен упрощают отправку сообщения электронной почты. КлассMailMessage представляет сообщение электронной почты и имеет такие свойства, как To, From, Subject, Bodyи Attachments. SmtpClass Используется для отправки MailMessage объекта с помощью указанного SMTP-сервера; параметры SMTP-сервера можно указать программным или декларативным способом в элементе<system.net>Web.config fileв . Дополнительные сведения об отправке сообщений электронной почты в приложении ASP.NET проверка в статьях Отправка Email с сайта веб-страницы ASP.NET и Вопросы и ответы по System.Net.Mail.

Примечание

Элемент <system.net> содержит параметры SMTP-сервера, используемые классом при отправке SmtpClient сообщения электронной почты. Вероятно, у вашей компании по размещению веб-сайтов есть SMTP-сервер, который можно использовать для отправки электронной почты из приложения. Дополнительные сведения о параметрах SMTP-сервера, которые следует использовать в веб-приложении, см. в разделе поддержки вашего веб-узла.

Добавьте следующий код в Application_Error обработчик событий, чтобы отправить разработчику сообщение электронной почты при возникновении ошибки:

Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
    ' Get the error details
    Dim lastErrorWrapper As HttpException = _
        CType(Server.GetLastError(), HttpException)
    
    Dim lastError As Exception = lastErrorWrapper
    If lastErrorWrapper.InnerException IsNot Nothing Then
        lastError = lastErrorWrapper.InnerException
    End If

    Dim lastErrorTypeName As String = lastError.GetType().ToString()
    Dim lastErrorMessage As String = lastError.Message
    Dim lastErrorStackTrace As String = lastError.StackTrace

    Const ToAddress As String = "support@example.com"
    Const FromAddress As String = "support@example.com"
    Const Subject As String = "An Error Has Occurred!"

    ' Create the MailMessage object
    Dim mm As New MailMessage(FromAddress, ToAddress)
    mm.Subject = Subject
    mm.IsBodyHtml = True
    mm.Priority = MailPriority.High
  mm.Body = string.Format( _
"<html>" & vbCrLf & _
"  <body>" & vbCrLf & _
"  <h1>An Error Has Occurred!</h1>" & vbCrLf & _
"  <table cellpadding=""5"" cellspacing=""0"" border=""1"">" & vbCrLf & _
"  <tr>" & vbCrLf & _
"  <tdtext-align: right;font-weight: bold"">URL:</td>" & vbCrLf & _
"  <td>{0}</td>" & vbCrLf & _
"  </tr>" & vbCrLf & _
"  <tr>" & vbCrLf & _
"  <tdtext-align: right;font-weight: bold"">User:</td>" & vbCrLf & _
"  <td>{1}</td>" & vbCrLf & _
"  </tr>" & vbCrLf & _
"  <tr>" & vbCrLf & _
"  <tdtext-align: right;font-weight: bold"">Exception Type:</td>" & vbCrLf & _
"  <td>{2}</td>" & vbCrLf & _
"  </tr>" & vbCrLf & _
"  <tr>" & vbCrLf & _
"  <tdtext-align: right;font-weight: bold"">Message:</td>" & vbCrLf & _
"  <td>{3}</td>" & vbCrLf & _
"  </tr>" & vbCrLf & _
"  <tr>" & vbCrLf & _
"  <tdtext-align: right;font-weight: bold"">Stack Trace:</td>" & vbCrLf & _
"  <td>{4}</td>" & vbCrLf & _
"  </tr> " & vbCrLf & _
"  </table>" & vbCrLf & _
"  </body>" & vbCrLf & _
"</html>", _
  Request.RawUrl, _
  User.Identity.Name, _
  lastErrorTypeName, _
  lastErrorMessage, _
  lastErrorStackTrace.Replace(Environment.NewLine, "<br />"))

    'Attach the Yellow Screen of Death for this error
    Dim YSODmarkup As String = lastErrorWrapper.GetHtmlErrorMessage()
    If Not String.IsNullOrEmpty(YSODmarkup) Then
        Dim YSOD As Attachment = _
            Attachment.CreateAttachmentFromString(YSODmarkup, "YSOD.htm")
        mm.Attachments.Add(YSOD)
    End If

    ' Send the email
    Dim smtp As New SmtpClient()
    smtp.Send(mm)
End Sub

Хотя приведенный выше код довольно длинный, основная его часть создает 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. Разработчику отправляется уведомление Email при возникновении необработанного исключения
(Щелкните для просмотра полноразмерного изображения)

Снимок экрана: уведомление по электронной почте, полученное разработчиком при возникновении необработанного исключения.

Рис. 3. Уведомление Email включает сведения об исключении 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 кодом:

Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
    ' Get the error details
    Dim lastErrorWrapper As HttpException = _
        CType(Server.GetLastError(), HttpException)

    If lastErrorWrapper.GetHttpCode() = 404 Then
        Server.Transfer("~/ErrorPages/404.aspx")
    Else
        Server.Transfer("~/ErrorPages/Oops.aspx")
    End If
End Sub

Теперь при возникновении Application_Error необработанного исключения обработчик событий передает управление на соответствующую пользовательскую страницу ошибок на основе кода состояния HTTP. Так как управление было передано, пользовательская страница ошибок имеет доступ к необработанным сведениям об исключении через Server.GetLastError и может уведомить разработчика об ошибке и записать в журнал ее сведения. Вызов Server.Transfer останавливает подсистему ASP.NET перенаправление пользователя на пользовательскую страницу ошибок. Вместо этого содержимое настраиваемой страницы ошибок возвращается в качестве ответа на страницу, которая вызвала ошибку.

Сводка

При возникновении необработанного исключения в веб-приложении ASP.NET среда выполнения ASP.NET вызывает Error событие и отображает настроенную страницу ошибки. Мы можем уведомить разработчика об ошибке, записать в журнал ее сведения или обработать ее каким-либо другим способом, создав обработчик событий для события Error. Существует два способа создания обработчика событий для HttpApplication таких событий, как Error: в Global.asax файле или из http-модуля. В этом руководстве показано, как создать Error обработчик событий в Global.asax файле, который уведомляет разработчиков об ошибке с помощью сообщения электронной почты.

Создание обработчика Error событий полезно, если необходимо обрабатывать необработанных исключений каким-либо уникальным или настраиваемым способом. Однако создание собственного Error обработчика событий для регистрации исключения или уведомления разработчика не является наиболее эффективным использованием вашего времени, так как уже существуют бесплатные и простые в использовании библиотеки ведения журнала ошибок, которые можно настроить за считанные минуты. В следующих двух учебниках рассматриваются две такие библиотеки.

Счастливое программирование!

Дополнительные материалы

Дополнительные сведения по темам, рассматриваемым в этом руководстве, см. в следующих ресурсах: