Как я могу поймать код состояния HTTP ошибки сервера в универсальный пользовательский вид ошибки в ASP.NET в MVC


Я пытаюсь реализовать общую пользовательскую страницу ошибок в ASP.NET MVC 4. Я в основном настраиваю макет ошибки, который определяет Раздел для вывода кода состояния http ответа.

Представление, в котором я хочу, чтобы мои ошибки заканчивались, наследует такой макет и просто добавляет сообщение, которое приходит из его модели, которая была создана и передана в вызове View() в контроллере (с именем "Error"), который я настроил для обработки пользовательских ошибок в интернете.конфиг.
<customErrors defaultRedirect="/Error" mode="On"> 
</customErrors>

Тот самый пользовательский контроллер ошибок :

public class ErrorController : Controller
{
    public ActionResult Index()
    {
        return View(new CustomErrorViewModel(Response.Status));
    }
}

Пользовательский вид ошибки :

@{
    Layout = "~/Views/Shared/_CustomErrorLayout.cshtml";
}

@using System.Web.Configuration;
@using System.Configuration;
@using MVC_Tests.Models;
@model CustomErrorViewModel

@section HttpCode { @Response.StatusCode }

@Model.Status

Расположение:

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
    <link href="~/Content/CustomError.css" rel="stylesheet" />
</head>
<body>
    <div id="divError">
        <h1>
            <span>Error &nbsp;</span>
            @RenderSection("HttpCode")
        </h1>
        <div id="divErrorMessage">
            <p>@RenderBody()</p>
        </div>
    </div>
</body>
</html>

Ошибка, которую я пытаюсь обработать, - это простое деление на ноль, которое я добавил к действию Home Index. Обратите внимание, что я хочу, чтобы одно представление обрабатывало различные коды ошибок состояния http сервера (семейство 500). я знаю, что иметь разные представления для каждого отдельного кода состояния http работает, я после одного представления для обработки нескольких кодов.

В пользовательская обработка ошибок работает, я заканчиваю в желаемом представлении-но , как отмечалось выше, я ожидал, что выведу код состояния http ошибки. Вместо этого я всегда показываю 200 (OK), что, согласно моему пониманию и отладке, происходит потому, что:

1.Во-первых, при спотыкании с делением на ноль возникает исключение.

2. теперь происходит редирект, из-за моей паутины.инструкции по настройке для обработки ошибок настраиваемым способом (так как нет конкретных в Сети был указан код состояния http.config, я обрабатываю каждый код ошибки состояния http в том же контроллере / представлении ("/Error"). Здесь важно то, что перенаправление являетсяновым запросом.

3. перенаправление с шага 2 отправляет меня к контроллеру ошибок, а затем отправляет меня в свое представление, которое визуализируется.

4. при рендеринге представления код состояния http вставляется в раздел, определяемый макетом, добавляется мое пользовательское сообщение и выводится часть кода состояния http, как я уже сказал: 200 (OK). Почему, если ошибка на стороне сервера 500 была принудительно выброшена ? Потому что, если я не ошибаюсь, представление отображается в другом канале запроса, перенаправляющем, и в перенаправлении - никаких ошибок не происходит - и я получаю ответ состояния 200 (OK).

Я перечитал это сообщение Дино Эспозито об обработке ошибок в asp.net mvc, но я не хочу добавлять фильтры (OnException и HandleError attribute solutions) ко всем контроллерам приложения (Я мог бы создать новый базовый контроллер, который имеет такой фильтр, и заставить все остальные наследовать от него, но это также требует изменения всех классов контроллеров). Последний подход, который он упоминает (handling global.событие Application_Error asax) я не уверен, что служит этой цели - я должен выдать ответ redirect".Redirect " оператор в обработчике, который превосходит гибкость в возможности установки пользовательских страниц в интернете.config (я все еще могу перенаправить на маршрут, определенный в интернете.конфиг, но мне интересно, не становится ли это слишком громоздким для того, что выглядит так просто).

Как лучше всего перехватить код состояния http ответа на любую ошибку сервера в моем пользовательском представлении ошибок ?

2 2

2 ответа:

Если вы используете IIS7+, я бы отключил "customerrors" следующим образом:

 <customErrors mode="Off" />

И использовать httpErrors так:

<system.webServer>
 <httpErrors errorMode="DetailedLocalOnly" existingResponse="Replace" defaultPath="/error">
     <remove statusCode="404" />
     <error statusCode="404" path="/error/notfound" responseMode="ExecuteURL" />
 </httpErrors>
....

Это позволяет получить страницу ошибки без изменения url с кодом состояния 404, используя следующее в контроллере:

public class ErrorController : Controller
{
public ActionResult notfound()
    {
        Response.TrySkipIisCustomErrors = true;
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View("OneErrorViewToRuleThemAll");
    }
}

ПС. "errorMode" должен измениться на "Custom", чтобы увидеть его локально....в зависимости от локальной настройки (например, если вы используете IISExpress), вы можете не увидеть правильную ошибку, пока не загрузите ее на живой сервер.

Pps. ты может иметь одно представление "OneErrorViewToRuleThemAll" для обработки вывода на экран любых кодов состояния, которые вы решите обрабатывать таким образом. Каждое действие ErrorController будет заканчиваться на этом представлении.

Решение, которое я искал (после того, как был на грани отказа), описано здесь.

Подведение итогов:

  1. Установите свою паутину.config для перенаправления на действие контроллера для каждой ошибки, которую вы хотите обработать.
  2. Установите свойство TryToSkipCustomErrors объекта Response в true, в каждом действии, определенном в 1.
  3. прокомментируйте строку filters.Add(new HandleErrorAttribute()); из вашего filterConfig.cs-файл.

Использование этот подход мне наконец-то удалось сделать редирект на пользовательскую страницу для ошибки 500. похоже, что IIS по умолчанию пропускает 500, потому что настройка пользовательской страницы для ошибки 404 не требует ни шагов 2, ни 3.

Итак, в конце концов, для каждого кода состояния http, который я хочу отобразить пользовательскую страницу, Я создаю действие контроллера, устанавливаю описанные свойства соответственно, а затем перенаправляю в то же представление, для всех действий-где я отображаю @Response.Статус, делающий его достаточным универсальное решение для меня.