Во время выполнения приложения ASP.NET может возникнуть исключение, которое не обрабатывается в коде приложения, т.к. от ошибок или невнимательности никто не застрахован. :) Но стандартная страница ASP.NET, сообщая об ошибке, выглядит достаточно пугающе для рядового пользователя. Решением может выступить создание для нее дружественного интерфейса.
Решение
Для этого придется внести изменения в Global.asax. Данный файл содержит методы, обрабатывающие события уровня приложения и сессии. Нам нужно будет работать с методом Application_Error. Кроме того, нужно будет создать страницу, назовем ее Error.aspx, сообщающую о возникшей ошибке.
Код Global.asax.cs
Здесь возможно несколько подходов к реализации процесса оповещения об ошибке.
1. Сообщить пользователю об ошибке и предоставить информацию о ней. В данном случае код выглядит так:
if (lastError != null) { //Записываем непосредственно исключение, вызвавшее данное, в //Session для дальнейшего использования Session[ErrorException] = lastError.InnerException; }
// Обнуление ошибки на сервере Server.ClearError();
// Перенаправление на свою страницу отображения ошибки Response.Redirect(Error.aspx); } catch (Exception) { // если мы всёже приходим сюда - значит обработка исключения // сама сгенерировала исключение, мы ничего не делаем, чтобы // не создать бесконечный цикл Response.Write(К сожалению произошла критическая ошибка. Нажмите кнопку Назад в браузере и попробуйте ещё раз. ); } }
//Добавляем информацию о предыдущей посещенной странице if(Context.Request.UrlReferrer != null) { Message += nnReferer: + Context.Request.UrlReferrer.ToString(); }
//Добавляем информацию о пользователе, в случае если успешно прошел процесс аутентификации if(Context.User.Identity.IsAuthenticated) { Message += nnUser: + Context.User.Identity.Name; }
Message += nnnnEXCEPTION: + 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
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.
Его имя должно совпадать с указанным в коде. В нашем случае это ErrorSample.
3. При помощи комбинации вышеперечисленных методов
Страница Error.aspx
Страница Error.aspx, как уже говорилось выше, должна непосредственно выводить сообщение об ошибке. Для этого добавим на нее Label и назовем его lblMessage. Обработку исключения (напомню, что мы поместили его в сессию), будем производить в методе Page_Load. Его текст приведен ниже.
//отобразим пользователю общее сообщение об ошибке 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);
Так же, сужествует дополнительная возможность: перенаправление на определенную страницу в зависимости от кода HTTP ошибки. Это позволяет делать параметр “error“. Его атрибут statusCode задает код ошибки, а redirect задает страницу, на которую следует перенаправить пользователя. Например, в случае, если запрашиваемый ресурс не найден (код ошибки 404), перенаправим пользователя на страницу Error404.html, оповещающая пользователя о случившемся происшествии. Web.config будет выглядить так: