Есть ли способ включить пользовательские ошибки в ASP MVC 4?

Я пробовал все возможные способы, которые нашел здесь (Как заставить пользовательские страницы ошибок работать в ASP.NET MVC 4) или здесь: http://benfoster.io/blog/aspnet-mvc-custom-error-pages, здесь: http://www.secretgeek.net/custom_errors_mvc, но, похоже, у меня ничего не работает.

Я упростил его до миниума, но все еще получаю уродливое стандартное сообщение об ошибке при переходе на несуществующую страницу.

Мой файл Error.cshtml находится в папке Views\Shared и выглядит так:

<div>
    <span>Error occurred</span>
</div>

пробовал также:

@model System.Web.Mvc.HandleErrorInfo
@{
    ViewBag.Title = "Parking & Ticket Scan Information - Error";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<div>
    <span>Error occurred</span>
</div>

Мой web.config содержит:

<customErrors mode="On" defaultRedirect="~/Error">
    <error redirect="~/Error/NotFound" statusCode="404" />
</customErrors>

но я также пробовал:

<customErrors mode="On" defaultRedirect="~/Error">
</customErrors>

Мой ErrorController похож на:

public class ErrorController : Controller
{
    [HandleError]
    public ViewResult Index()
    {
        return View();
    }
}

(с или без атрибута [HandleError], с и без

public ViewResult NotFound()
{
    Response.StatusCode = 404;  //you may want to set this to 200
    return View("NotFound");
}

Позже я добавил также маршрутизацию в Global.asax:

route.MapRoute(имя: "PageNotFound", URL-адрес: "{*url}", значения по умолчанию: новый {контроллер = "Ошибка", действие = "Индекс", id = UrlParameter.Optional}

Кажется, ничто не заставляет IIS показывать пользовательскую ошибку. Что еще я пробовал? Разумеется, закомментированы фильтры.Add(new HandleErrorAttribute()); Error.cshtml перемещен в папку Views.

Существуют ли какие-либо другие подходы, которые я мог бы использовать, чтобы включить его?


person Radek Strugalski    schedule 19.07.2017    source источник
comment
Я пробовал решение Бена Фостера, и оно работает. Некоторые из других решений, которые я пробовал, не работают, если IIS сначала перехватывает ошибку - в этом случае ваше приложение не сможет обработать ошибку, и вы увидите ошибку по умолчанию.   -  person Jasen    schedule 19.07.2017


Ответы (2)


Вы всегда можете сделать что-то вроде этого

public class HandleUnauthorizedAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        base.OnException(filterContext);

        if (filterContext.Exception.GetType() != typeof (SecurityException)) return;

        var controllerName = (string) filterContext.RouteData.Values["controller"];
        var actionName = (string) filterContext.RouteData.Values["action"];
        var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);

        filterContext.Result = new ViewResult
        {
            ViewName = "Unauthorized",
            ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
            TempData = filterContext.Controller.TempData
        };
        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.StatusCode = 403;
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}

Этот код фиксирует все SecurityExceptions и перенаправляет их на пользовательскую страницу ошибок с заполненным HandleErrorInfo.

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

Затем пропишите фильтры при запуске

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleUnauthorizedAttribute());
        //more filters if you define them.
    }
}

И создайте свои представления в /Shared/Views

person Fran    schedule 19.07.2017

Таким образом, единственным возможным решением, которое я нашел до сих пор, было добавление представления, соответствующего имени метода действия ErrorController внутри папки View\Error. Эта крошечная деталь, кажется, отсутствует во всех других руководствах.

Итак, теперь у меня есть ErrorContoller.cs:

public class ErrorController : Controller
{
    public ActionResult ErrorDefault()
    {
        return View();
    }
}

И ErrorDefault.cshtml в папке Views\Error:

@{
    ViewBag.Title = "ErrorDefault";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>ErrorDefault</h2>

И web.config:

<customErrors mode="On" defaultRedirect="~/Error/ErrorDefault">
</customErrors>

Если вы забудете поместить свое представление в подпапку, соответствующую имени контроллера, оно просто не будет работать в MVC 4.0.

Добавлять отдельный Route в RouteConfig не нужно.

Я надеюсь, что кто-то найдет это полезным. :)

person Radek Strugalski    schedule 20.07.2017
comment
Если вы забудете поместить свое представление в подпапку, соответствующую имени контроллера, оно просто не будет работать в MVC — так было всегда. - person Tomas Voracek; 12.08.2017