Поделиться через


Обработка необработанных исключений (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.

Sceenshot, который выделяет глобальную точку S A X-файл.

Рис. 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 событий BeginRequestAuthenticateRequestи Errorсоответственно. Существуют также обработчики событий с именем Application_Start, Application_EndSession_Startи Session_End, которые являются обработчиками событий, которые запускаются при запуске веб-приложения, когда запускается новый сеанс, когда приложение заканчивается, и когда сеанс заканчивается соответственно. ФайлGlobal.asax, созданный в WSP Visual Studio, содержит только Application_Errorобработчики событий , и Session_StartApplication_EndSession_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, , SubjectBodyи 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. Разработчик отправляет уведомление по электронной почте при возникновении необработанного исключения
(Щелкните, чтобы просмотреть изображение полного размера)

Снимок экрана: уведомление по электронной почте содержит сведения об исключении Y S O D в виде вложения.

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

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

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

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