Пользовательские ошибки ASP.NET MVC

18

Моя цель - создать обработку ошибок в приложении, которая обрабатывает все управляемые ошибки, а не только связанные с MVC. Поэтому я не использую шаблон HandleErrorAttribute, потому что он предназначен только для ошибок MVC, а не для других управляемых ошибок.

В моем Global.asax у меня есть:

protected void Application_Error()
{
    string displayError = ConfigurationManager.AppSettings["DisplayError"];
    NameValueCollection serverVariables;
    int loop1, loop2;
    StringBuilder serverVariableKeys = new StringBuilder();
    Exception exception = Server.GetLastError();
    HttpException httpException = exception as HttpException;

    if (HttpContext.Current != null)
    {
            // loop through and get server vars
    }

    if (exception != null)
        // Log Error

    // Redirect to Error page if set to basic mode
    if (!string.IsNullOrWhiteSpace(displayError) && displayError.ToLower() == "basic")
    {
        Response.Clear();
    Server.ClearError(); // needed for redirect to work

    var routeData = new RouteData();
    routeData.Values["controller"] = "Error";
    routeData.Values["action"] = "General";
    routeData.Values["exception"] = exception;
    Response.StatusCode = 500;

    if (httpException != null)
    {
       Response.StatusCode = httpException.GetHttpCode();
       switch (Response.StatusCode)
        {
        case 403:
          routeData.Values["action"] = "Http403";
          break;
            case 404:
           routeData.Values["action"] = "Http404";
           break;
        }
    }

    IController errorsController = new Controllers.ErrorController();
    var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
    errorsController.Execute(rc);
    }
}

У меня есть ErrorController, который имеет General, Http403 и Http404 Действия. У меня есть мнения, соответствующие каждому действию.

В моем web.config у меня есть:

  <system.web>  
    <!-- removed bits to reduce space -->
    <customErrors mode="On" />
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules >
      <remove name="UrlRoutingModule-4.0" />
      <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
      <remove name="Session"/>
      <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition=""/>
    </modules>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
    <httpErrors errorMode="Detailed" />
  </system.webServer>

Это работает для многих сценариев, связанных с управляемым кодом, но когда IIS берет на себя, например, плохой статический вызов файла (example.com/BadFileName.gif), он возвращает ошибку из IIS, которая раскрывает данные сервера, такие как путь к локальному файлу, Это происходит из-за следующей строки в файле web.config:

<httpErrors errorMode="Detailed" />

Но когда я устанавливаю значение errorMode для других значений, таких как Custom, или просто удаляю строку, моя пользовательская обработка ошибок перестает работать, и сообщения об ошибках IIS по умолчанию возвращаются для всех, включая ошибки управляемого кода.

Я пробовал несколько вещей, чтобы добраться до пользовательских ошибок, чтобы работать без этого параметра без везения, в том числе:

  • Настройка CustomError - mode="Off"
  • Определение узлов ошибок в CustomError для перенаправления на мои контроллеры
  • Определение узлов ошибок в httpErrors для перенаправления на мои контроллеры

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

Сведения о приложении:

  • ASP.NET MVC 4.0
  • Хостинг на IIS 7.5 (Предварительный просмотр веб-сайта Azure)

Есть ли способ не использовать <httpErrors errorMode="Detailed" /> и сделать эту работу?

  • 0
    обрабатывает все управляемые ошибки Что делать, если Razer выдает исключение (неправильная конфигурация, отсутствует сборка и т. д.). Что вы ожидаете отрисовать страницу с ошибкой?
  • 0
    Если в Razor есть ошибка, по умолчанию используется ошибка IIS. Это верный момент, поскольку у вас может быть ошибка во время выполнения, но я сохранил свои страницы ошибок простыми, около 3 строк кода Razor.
Показать ещё 2 комментария
Теги:
asp.net-mvc
asp.net-mvc-4

2 ответа

33
Лучший ответ

Причина, по которой вы видите поведение, вероятно, что ваш обработчик Application_Error правильно вызывается (и вызывает ваш контроллер), но затем IIS перехватывает ошибку 500 и отображает собственную страницу ошибок. (хотя также возможно, что ваш обработчик Application_Error сам выбрасывает Exception, что вы хотите исключить)

Поскольку вы хотите обрабатывать все ошибки (например, упомянутую статическую ошибку файла), вы, вероятно, не сможете использовать ASP.NET или ASP.NET MVC для первоначального обнаружения ошибок. Не все ошибки поступают из вашего приложения!

Самое лучшее, что нужно сделать, это ориентироваться на обработку ошибок IIS 7.5 столько, сколько вы можете, а не пытаться слишком рано вовлечь себя в себя. Пусть IIS сделает первоначальное обнаружение ошибок для вас, и это намного проще.

Попробуйте поместить следующее в свой web.config, заменив существующий httpErrors node: -

<httpErrors errorMode="Custom" existingResponse="Replace">
  <clear />
  <error statusCode="400" responseMode="ExecuteURL" path="/Error" />
  <error statusCode="403" responseMode="ExecuteURL" path="/Error/Forbidden" />
  <error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
  <error statusCode="500" responseMode="ExecuteURL" path="/Error" />
</httpErrors>

Удалите customErrors node полностью. Это не нужно.

Помните и убедитесь, что ваш контроллер ошибок задает правильный код состояния: -

public ActionResult Forbidden()
{
    Response.StatusCode = 403;
    return this.View();
}

После этого вы можете отбросить все, кроме выхода из вашего обработчика Application_Error, хотя я думаю, что вам лучше всего создать свой собственный HttpModule; установка runAllManagedModulesForAllRequests в модулях node в вашем web.config поможет вам уловить ошибки, которые в противном случае проскальзывают.

У меня есть эта настройка (хотя я лично использую elmah для ведения журнала), работающую на предварительном просмотре веб-сайтов Azure, и она захватывает все, за исключением, очевидно, любых ошибок, возникающих из-за невозможности разобрать web.config.

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

  • 3
    Кажется, что ключом является существующий атрибут Replace = "Replace", который я пропустил. Отличные предложения, единственное, на что я хотел бы отодвинуться, это предложение runAllManagedModulesForAllRequests = "true". Я читал, что настройка снижает производительность и создает несколько ошибок. Вместо этого предлагается установить preCondition = "" - недостатком является то, что вы должны ссылаться на каждый модуль.
  • 2
    существующиеResponse = "Заменить" спасли день!
Показать ещё 8 комментариев
0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню