Всё мы знаем, что в ASP.NET MVC есть такой атрибут
Но нигде, в том же MSDN не сказано (ткните меня носом дайте ссылку где это написано, если я просмотрел), что он обрабатывает только исключения, устанавливающие код ответа сервера в 500.
Посмотрев на исходный код
Не знаю, как вам, а мне удобнее при возникновении исключения, чтобы пользователи видели специальную страницу для этого, а не «жёлтую страницу смерти» или вообще как браузер отображает стандартную для него страницу с кодом ответа сервера (зависит от настроек в Web.config, но об этом позже).
Создание собственного аналога
Итак, мы выяснили, что стандартный
Можно конечно, создать класс наследуя его от интерфейса
Для начала скажу, что это код стандартного
Собственно, что он делает:
Класс наш готов, теперь заменим стандартный атрибут на наш. Сделаем это через глобальные фильтры, чтобы нам не писать его каждому контроллеру или действию контроллера. В данном случае это не критично, но в реальности может пригодиться. Итак, идём в Global.asax.cs и прописываем вместо стандартного фильтра, наш только что созданный атрибут:
Теперь, чтобы убедится, что наш фильтр работает и передаёт необходимые данные во
И добавим в Web.config (который находится в корне) в секцию
Этой строчкой мы включаем пользовательскую обработку ошибок, точнее пользовательские страницы для ошибок.
Теперь нам необходимо вызвать исключение, я сделаю это в действии стандартного контроллера (созданного студией):
Всё! Запускаем проект, переходим в раздел «About» и видим, что наш атрибут отработал корректно.

HandleErrorAttribute, который как сказано в MSDN Представляет атрибут, используемый для обработки исключения, вызываемого методом действия.
Но нигде, в том же MSDN не сказано (
Посмотрев на исходный код
HandleErrorAttribute легко убедиться в этом. Там имеются следующие строки:// If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method), // ignore it. if (new HttpException(null, exception).GetHttpCode() != 500) { return; }
Не знаю, как вам, а мне удобнее при возникновении исключения, чтобы пользователи видели специальную страницу для этого, а не «жёлтую страницу смерти» или вообще как браузер отображает стандартную для него страницу с кодом ответа сервера (зависит от настроек в Web.config, но об этом позже).
Создание собственного аналога HandleErrorAttribute
Итак, мы выяснили, что стандартный
HandleErrorAttribute нам не подходит, ну что же, создадим свой.Можно конечно, создать класс наследуя его от интерфейса
IExceptionFilter, но нас в общем то устраивает поведение стандартного HandleErrorAttribute, если бы он обрабатывал все исключения. А раз нас почти всё устраивает, будет наследовать наш класс от неугодного нам HandleErrorAttribute.public class HandleAllErrorAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } // If custom errors are disabled, we need to let the normal ASP.NET exception handler // execute so that the user can see useful debugging information. if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) { return; } Exception exception = filterContext.Exception; if (!ExceptionType.IsInstanceOfType(exception)) { return; } string controllerName = (string)filterContext.RouteData.Values["controller"]; string actionName = (string)filterContext.RouteData.Values["action"]; HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName); filterContext.Result = new ViewResult { ViewName = View, MasterName = Master, ViewData = new ViewDataDictionary<HandleErrorInfo>(model), TempData = filterContext.Controller.TempData }; filterContext.ExceptionHandled = true; filterContext.HttpContext.Response.Clear(); filterContext.HttpContext.Response.StatusCode = new HttpException(null, exception).GetHttpCode(); // Certain versions of IIS will sometimes use their own error page when // they detect a server error. Setting this property indicates that we // want it to try to render ASP.NET MVC's error page instead. filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; } }
Для начала скажу, что это код стандартного
HandleErrorAttribute, за исключением нескольких строк, проверяющих на HttpStatusCode.Собственно, что он делает:
- Проверяет входные параметры на валидность
- Проверяет включены ли
customErrors - Заполняет данными класс
HandleErrorInfo - Создаёт новый
ViewResult, заполняет данными и присваивает вместо текущего - Очищает ошибки сервера и устанавливает код ответа сервера
Класс наш готов, теперь заменим стандартный атрибут на наш. Сделаем это через глобальные фильтры, чтобы нам не писать его каждому контроллеру или действию контроллера. В данном случае это не критично, но в реальности может пригодиться. Итак, идём в Global.asax.cs и прописываем вместо стандартного фильтра, наш только что созданный атрибут:
filters.Add(new HandleAllErrorAttribute());
Испытание
Теперь, чтобы убедится, что наш фильтр работает и передаёт необходимые данные во
View, несколько изменим стандартный ~/Views/Shared/Error.cshtml:@model System.Web.Mvc.HandleErrorInfo @{ ViewBag.Title = "Error"; } <h2> Sorry, an error occurred while processing your request. </h2> <h3>@Model.Exception.Message</h3>
И добавим в Web.config (который находится в корне) в секцию
System.Web следующую строку:<customErrors mode="On" defaultRedirect="Error" />
Этой строчкой мы включаем пользовательскую обработку ошибок, точнее пользовательские страницы для ошибок.
Теперь нам необходимо вызвать исключение, я сделаю это в действии стандартного контроллера (созданного студией):
public ActionResult About() { throw new HttpException(403, "Доступ запрещён!"); return View(); }
Всё! Запускаем проект, переходим в раздел «About» и видим, что наш атрибут отработал корректно.

