Обработка ошибок для всего сайта в ASP.NET MVC

bughunt
Этим постом я расскажу, как можно отлавливать все исключения приложения и выводить для них различные страницы ошибок, например отображать представление ~/Views/Shared/Error.cshtml, которое используется для отображения необработанных в контроллерах исключений атрибутом HandleErrorAttribute.

Зачем?

Как я уже написал, HandleErrorAttribute обрабатывает только необработанные исключения контроллеров. Таким образом, если исключение произошло где-то в другом месте, то пользователь увидит страницу ошибки, сгенерированную сервером или страницу ошибки, указанную в разделе  customErrors файла Web.config. Также атрибут обрабатывает HTTP исключения только с кодом 500.
Для обработки несуществующих действий можно воспользоваться методом HandleUnknownAction класса Controller , который можно переопределить и написать логику для отображения страницы ошибки. Но этот метод не будет работать в том случае, если запрашиваемый URL не обрабатывается каким либо контроллером, т.е. ошибка 404 сгенерируется сервером и метод HandleUnknownAction не будет вызван и в таком случае пользователь увидит стандартную ошибку сервера или опять же указанную в разделе customErrors файла Web.config.
Все эти механизмы работают хорошо для некоторого круга задач, но иногда требуется иметь полный контроль над ошибками и выводить определённую страницу в зависимости от произошедшей ситуации.

Что делать?

Итак, что бы добиться вышеописанного функционала, будем обрабатывать все ошибки пришедшие в метод Application_Error файла Global.asax и отображать нужное представление в зависимости от типа ошибки.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
...
protected void Application_Error(object sender, EventArgs e)
{
    HttpContext ctx = HttpContext.Current;
    Exception ex = ctx.Server.GetLastError();
    ctx.Response.Clear();
    RequestContext rc = ((MvcHandler)ctx.CurrentHandler).RequestContext;
    IController controller = new HomeController(); // Тут можно использовать любой контроллер, например тот что используется в качестве базового типа
    var context = new ControllerContext(rc, (ControllerBase)controller);
    var viewResult = new ViewResult();
    var httpException = ex as HttpException;
    if (httpException != null)
    {
        switch (httpException.GetHttpCode())
        {
            case 404:
                viewResult.ViewName = "Error404";
                break;
            case 500:
                viewResult.ViewName = "Error500";
                break;
            default:
                viewResult.ViewName = "Error";
                break;
        }
    }
    else
    {
        viewResult.ViewName = "Error";
    }
    viewResult.ViewData.Model = new HandleErrorInfo(ex, context.RouteData.GetRequiredString("controller"), context.RouteData.GetRequiredString("action"));
    viewResult.ExecuteResult(context);
    ctx.Server.ClearError();
}
...
В коде выше мы сделали так, что для ошибок 404 и 500 будет выводиться индивидуальное представление, а все остальные ошибки будут отображаться посредствам представление Error. В качестве модели я использую класс HandleErrorInfo, который использует атрибут HandleUnknownAction, этого вполне достаточно для передачи информации о произошедшей ошибке.
Ниже код и скриншоты представлений ошибок.
Ошибка 404:
1
2
3
4
5
@{
    ViewBag.Title = "Page not found. (Error 404)";
}
<h2>Sorry, the page you have requested is not available or was deleted from server.</h2>




Ошибка 500:
1
2
3
4
5
@{
    ViewBag.Title = "HTTP Error 500 Internal server error";
}
<h2>We're sorry, but something went wrong.</h2>




Все необработанные исключения:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@model System.Web.Mvc.HandleErrorInfo
@{
    ViewBag.Title = "Error | " + Model.Exception.Message;
}
<h2>
    Sorry, an error occurred while processing your request.
</h2>
<h3>@Model.Exception.GetType()</h3>
<div>
  <span style="color:#f00">@Model.Exception.Message</span>
  <pre style="overflow: auto; background-color: #FFFB97; color: #134D82; font-size: 11px;">@Model.Exception.StackTrace</pre>
</div>




Злоключение

Так же нужно убрать регистрацию фильтра HandleErrorAttribute или установить<customErrors mode=”Off”></customErrors> в файле Web.config, т.к. при возникновении ошибки 500, она будет обработана атрибутом и выведет ошибку по средствам представления Error.
Код рабочего проекта можно скачать тут.

http://hystrix.com.ua/2011/01/23/error-handling-for-all-asp-net-mvc3-application/

Комментарии

Популярные сообщения