Обработка ошибок в ASP

Обработка ошибок в ASP

В данной статье рассказывается о нескольких основных способах обработки ошибок в ASP.NET приложениях.

Oleg Temnov

Проблема

Во время выполнения приложения ASP.NET может возникнуть исключение, которое не обрабатывается в коде приложения, т.к. от ошибок или невнимательности никто не застрахован. :) Но стандартная страница ASP.NET, сообщая об ошибке, выглядит достаточно пугающе для рядового пользователя. Решением может выступить создание для нее дружественного интерфейса.

Решение

Для этого придется внести изменения в Global.asax. Данный файл содержит методы, обрабатывающие события уровня приложения и сессии. Нам нужно будет работать с методом Application_Error. Кроме того, нужно будет создать страницу, назовем ее Error.aspx, сообщающую о возникшей ошибке.

Код Global.asax.cs

Здесь возможно несколько подходов к реализации процесса оповещения об ошибке.

1. Сообщить пользователю об ошибке и предоставить информацию о ней. В данном случае код выглядит так:

protected void Application_Error(Object sender, EventArgs e)

{

            try

            {

                        //ловим последнее возникшее исключение

                        Exception lastError = Server.GetLastError();

 

                        if (lastError != null)

                        {

                                   //Записываем непосредственно исключение, вызвавшее данное, в

                                   //Session для дальнейшего использования

                                   Session["ErrorException"] = lastError.InnerException;

                        }

                        // Обнуление ошибки на сервере

                        Server.ClearError();

                        // Перенаправление на свою страницу отображения ошибки

                        Response.Redirect("Error.aspx");

            }

            catch (Exception)

            {

                        // если мы всёже приходим сюда - значит обработка исключения

                        // сама сгенерировала исключение, мы ничего не делаем, чтобы

                        // не создать бесконечный цикл

                        Response.Write("К сожалению произошла критическая ошибка. Нажмите кнопку 'Назад' в браузере и попробуйте ещё раз. ");

            }

}

2. Сообщить администратору

2.1. При помощи электроннной почты

protected void Application_Error(Object sender, EventArgs e)

{

            try

            {

                        try

                        {

                                   System.Exception ex = Server.GetLastError();

                                   // Собираем необходимые данные

                                   String Message = "Main Error" + "\nDate & Time: " +

                                   DateTime.Now.ToString("F") + "\n\nURL: " + Request.Path +

                                   "\n\nQUERY: " + Request.QueryString + "\n\nMESSAGE: " +

                                    ex.Message + "\n\nBROWSER: " + Request.Browser.Browser +

                                    "\n\nIP Address: " + Request.UserHostAddress;

 

                                   //Добавляем информацию о предыдущей посещенной странице

                                   if(Context.Request.UrlReferrer != null)

                                   {

                                               Message += "\n\nReferer: " +

                                               Context.Request.UrlReferrer.ToString();

                                   }

                                   //Добавляем информацию о пользователе, в случае если успешно прошел процесс аутентификации

                                   if(Context.User.Identity.IsAuthenticated)

                                   {

                                               Message += "\n\nUser: " + Context.User.Identity.Name;

                                   }

                                   Message += "\n\n\n\nEXCEPTION: " + ex.ToString();

                                   System.Web.Mail.MailMessage mail = new System.Web.Mail.MailMessage();

                                   mail.To = "[e-mail адрес администратора]";

                                   mail.Subject = "Error in the Site";

                                   mail.Priority = System.Web.Mail.MailPriority.High;

                                   mail.BodyFormat = System.Web.Mail.MailFormat.Text;

                                   mail.Body = Message;

                                   // Здесь необходимо указать используемый SMTP сервер

                                   System.Web.Mail.SmtpMail.SmtpServer="[адрес SMTP сервера]";

                                   System.Web.Mail.SmtpMail.Send(mail);

                        }

                        catch {}

                        // Обнуление ошибки на сервере

                        Server.ClearError();

                        // Перенаправление на статическую html страницу, сообщающую об ошибке

                        // никаких данных об произошедшей ошибке ей не передается

                        Response.Redirect("Error.html");

            }

            catch

            {

                        // если мы всёже приходим сюда - значит обработка исключения

                        // сама сгенерировала исключение, мы ничего не делаем, чтобы

                        // не создать бесконечный цикл

                        Response.Write("К сожалению произошла критическая ошибка. Нажмите кнопку 'Назад' в браузере и попробуйте ещё раз. ");

            }

}

2.2. При помощи записи сообщения в журнал событий Windows

protected void Application_Error(Object sender, EventArgs e)

{

            try

            {

                        // Наименование ресурса, вызвавшего ошибку

                        string EventSourceName = "ErrorSample";

                        // Наименование LogView

                        string logName = "Application";

                       

                        System.Exception ex = Server.GetLastError();

                        System.Diagnostics.EventLog Log = new System.Diagnostics.EventLog(logName);

                        Log.Source = EventSourceName;

                        Log.WriteEntry(ex.InnerException.Message, System.Diagnostics.EventLogEntryType.Error);

           

                        // Обнуление ошибки на сервере

                        Server.ClearError();

                        // Перенаправление на статическую html страницу, сообщающую об ошибке

                        // никаких данных об произошедшей ошибке ей не передается

                        Response.Redirect("Error.html");

            }

            catch (Exception ex)

            {

                        // если мы всёже приходим сюда - значит обработка исключения

                        // сама сгенерировала исключение, мы ничего не делаем, чтобы

                        // не создать бесконечный цикл

                        Response.Write("К сожалению произошла критическая ошибка. Нажмите кнопку 'Назад' в браузере и попробуйте ещё раз. ");

            }

}

Здесь следует заметить, что зачастую приложение ASP.NET имеет достаточно ограниченный набор прав (что, в принципе, правильно с точки зрения безопасности). В связи с этим мы не сможем программно создать Event Source или проверить его существование в журнале событий Windows, если не будем использовать имперсонацию (impersonate). Решением может выступать ручное создание Event Source. Для этого внесем в реестр новый ключ, воспользовавшись программой regedit.

Нам необходимо добавить новый ключ по адресу

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ Eventlog\Application.

Его имя должно совпадать с указанным в коде. В нашем случае это ErrorSample.

3. При помощи комбинации вышеперечисленных методов

Страница Error.aspx

Страница Error.aspx, как уже говорилось выше, должна непосредственно выводить сообщение об ошибке. Для этого добавим на нее Label и назовем его lblMessage. Обработку исключения (напомню, что мы поместили его в сессию), будем производить в методе Page_Load. Его текст приведен ниже.

private void Page_Load(object sender, System.EventArgs e)

{

            try

            {

                        // возьмем информацию об исключении из сессии

                        Exception exc=(Exception)Session["ErrorException"];

                        string errorMsg = exc.Message;

                        string pageErrorOccured = Context.Request.UrlReferrer.ToString();

                        string exceptionType = exc.GetType().ToString();

                        string stackTrace = exc.StackTrace;

                       

                        // очистим переменную сессии

                        Session["ErrorException"] = null;

                        //отобразим пользователю общее сообщение об ошибке

                        lblMessage.Text = " К сожалению, произошла ошибка выполнения приложения.<br/><br/>";

                        lblMessage.Text =String.Format("{0} Чтобы попробовать ещё раз,

                        кликните <a href='{1}'>здесь</a>.<br/><br/>",lblMessage.Text,

                        pageErrorOccured);

                        //добавим конкретное сообщение об

                        lblMessage.Text = lblMessage.Text +

                        "Error Message: " + errorMsg +"\n"+

                        "Page Error Occurred: " + pageErrorOccured + "\n"+

                        "ExceptionType: " + exceptionType +"\n"+

                        "Stack Trace: " + stackTrace;

            }

            catch (Exception ex)

            {

                        //если исключение вызвано кодом, написанным выше

                        //выведем сообщение об ошибке и StackTrace

                        lblMessage.Text = ex.Message+" "+ex.StackTrace;

            }

}

Альтернатива

Следует заметить, что намного эффективнее будет использовать один из параметров файла web.config. Это позволит быстро (без изменения кода), менять ссылку страницы с сообщениями об ошибке или вообще убрать ее, в случае необходимости. Сссылка на нее задается с помощью атрибута defaultRedirect. Кроме того, при использовании данного атрибута в коде, следует убрать строки

// Обнуление ошибки на сервере

Server.ClearError();

А необходимость в следующих строках просто теряется, так как перенаправление теперь происходит автоматически.

// Перенаправление на страницу сообщающую об ошибке

Response.Redirect("Error.aspx");

Пример настройки web.config:

<customErrors mode="On" defaultRedirect="error.aspx"/>

Так же, сужествует дополнительная возможность: перенаправление на определенную страницу в зависимости от кода HTTP ошибки. Это позволяет делать параметр “error“. Его атрибут statusCode задает код ошибки, а redirect задает страницу, на которую следует перенаправить пользователя. Например, в случае, если запрашиваемый ресурс не найден (код ошибки 404), перенаправим пользователя на страницу Error404.html, оповещающая пользователя о случившемся происшествии. Web.config будет выглядить так:

<customErrors mode="On" defaultRedirect="error.aspx">

  <error statusCode="404" redirect="Error404.html"/>

</customErrors>