Картинка блога

Рано или поздно разработчик сталкивается с потребностью создания красивой страницы для отображения случайных и не случайных ошибок. Есть множество решений по этому поводу, большинство из них приходятся на обработчик события Application.OnError или Page.OnError. Сценарий такой:
пользователь заходит на какую-то страницу с ошибкой. В моем случае теперь можно считать ошибкой даже то, что не найдено ни одной записи в базе на запрос пользователя, скажем ошибка: No row found. Соответственно, страница кидает exception — MyCustomException(«No row found»). Далее, проблемой остается только правильно обработать ошибку и передать ее странице, которая все это красиво отобразит. Появляются следующие требования:

  1. Ошибка должна перехватываться со всех страниц приложения.
  2. Нужно обрабатывать только те ошибки, которые предназначены для перехвата
  3. Страница ошибки должна легко доступна для разработчика.
  4. Решение не должно требовать больших изменений в логике программы или массивного рефакторинга.

Пользовательский Exception

Для начала создадим базовый, а может и единственный — в зависимости от размера приложения.

public class CustomException: Exception
{
private string description;
public CustomException()
{
}
public CustomException(string message)
: base(message)
{
}
public CustomException(string message, string description)
: base(message)
{
this.description = description;
}

public string Description
{
get
{
if(String.IsNullOrEmpty(description))
{
return base.StackTrace;
}
return description;
}
}
}

Основной информацией будет Message и Description.

Модуль обработки ошибок.

Так как нам нужен обработчик на все страницы, подойдет HttpModule.

public class CustomExceptionHttpModule : IHttpModule
{
public void Dispose()
{
}

public void Init(HttpApplication app)
{
//При срабатывании этого события будем ловить наш exteption
app.Error += new EventHandler(app_Error);
}

void app_Error(object sender, EventArgs e)
{
HttpContext ctx = HttpContext.Current;

//Exception оборачивается в HttpException, по но нас интересует внутренняя ошибка.
ControllingException exception = ctx.Server.GetLastError().InnerException as CustomException;
if (exception == null) return; //Если это не CustomException передаем его обратно системе и не обрабатываем.

//Здесь уже понятно что это наш случай.
ctx.Server.ClearError(); //Чистим лист, чтобы система поняла что мы обработали ошибку.
ctx.Session[«LastError»] = exception; //Сохраняем ошибку в сессию, чтобы передать ее в ErrorPage.
ctx.Server.Transfer(«~/CustomErrorPage.aspx», true); //вызываем страницу ошибки.
}
}

После того как модуль создан, его нужно зарегистрировать в конфигурации web.config:

>
>
type=«MySite.CustomExceptionHttpModule , MySite» name=«CustomExceptionHttpModule»/>
>
>

Страница ошибки.

Теперь дело за малым, нужна страница, чтобы отобразить наш exception. С этим не должно возникнуть проблем, так как ошибка находится в сессии, до которой добраться проще простого. CustomErrorPage.aspx может выглядеть примерно так:

<%@ Page Language=«C#» Codebehind=«CustomErrorPage.aspx.cs» Inherits=«CustomErrorPage» %>

:TextBox id=«_messageTextBox» runat=«server» width=«400» Enabled=«false» />
>

:TextBox id=«_descriptionTextBox» runat=«server» width=«400» TextMode=«MultiLine» Rows=«15» Enabled=«false» />

Естественно что для страницы ошибки можно использовать Master Page.

Тогда CustomErrorPage.aspx.cs будет таким:

public partial class CustomErrorPage : Page
{
protected TextBox _messageTextBox;
protected TextBox _descriptionTextBox;

protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.Load += new EventHandler(CustomErrorPage_Load);
}

void CustomErrorPage_Load(object sender, EventArgs e)
{
ControllingException exception = Page.Session[«LastError»] as CustomException;
_messageTextBox.Text = exception.Message;
_descriptionTextBox.Text = exception.Description;
}
}

Метки:, , ,