Маршрутизация для настраиваемой страницы ошибок ASP.NET MVC 404

116

Я пытаюсь создать настраиваемую страницу ошибки HTTP 404, когда кто-то вводит URL-адрес, который не вызывает допустимое действие или контроллер в ASP.NET MVC, вместо того, чтобы отображать общую ошибку ASP.NET «Ресурс не найден».

Я не хочу использовать web.config для этого.

Могу ли я использовать какую-либо магию маршрутизации, чтобы отловить недействительные URL-адреса?

Обновление: я попробовал дать ответ, но по-прежнему получаю уродливое сообщение «Ресурс не найден».

Еще одно обновление: хорошо, видимо что-то изменилось в RC1. Я даже пробовал специально перехватить 404, HttpExceptionи он все равно выдает мне страницу «Ресурс не найден».

Я даже использовал функцию ресурса MvcContrib и ничего - та же проблема. Любые идеи?

dswatik
источник
Дубликат stackoverflow.com/questions/310580/…
Craig Stuntz
@Peter Это решение, которое я добавил, наряду с переопределением HandleUnknownAction, чтобы отображать представление страницы, не найденной, когда действие не существует, а затем встроенный пользовательский обработчик ошибок ASP.net для обработки чего-либо еще, что пользователи могут вводить .
dswatik
@pete Это тоже работает stackoverflow.com/questions/619895/…
dswatik
8
Я ненавижу, когда другие пользователи самонадеянны и говорят что-то вроде: «Зачем вам это нужно? Просто сделайте это ...» Но я бы посоветовал, если вам ничего не мешает использовать подход web.config, и он удовлетворяет ваши потребности, это стандартный и элегантный подход. Любые отзывы об этом подходе приветствуются, так как вполне могут возникнуть проблемы, о которых я не знаю.
Шон

Ответы:

10

Просто добавьте маршрут catch all в конец таблицы маршрутов и отобразите с ним любую страницу.

См.: Как я могу сделать перехват всех маршрутов для обработки запросов «404 страница не найдена» для ASP.NET MVC?

Алекс Рейтборт
источник
Я пробовал это, но все равно получаю уродливое сообщение о том, что ресурс не найден по умолчанию для ASP.NET ..
dswatik
3
Я не нахожу окончательного (и гибкого !!) решения этой проблемы ни в этом ответе, ни по предоставленной ссылке.
Питер,
4
Я тоже ... это похоже на хакерский ответ. Я ищу способ заставить customErrors вести себя так же, как в WebForms. Любые идеи?
JC Grubbs
1
Это и не работает, и плохо в принципе. Не работает, потому что не будет обнаруживать плохие URL-адреса, которые соответствуют одному из предыдущих шаблонов маршрутизации. Плохо в принципе, потому что преобразует то, что должно быть ошибкой, в ошибку. Перенаправление на страницу с названием «Ошибка» отличается от перенаправления на страницу с ошибкой. Вы хотите сохранить это как ошибку, зарегистрировать ошибку, а затем обработать ее как ошибку. Ошибки - ценная информация.
Мэтью,
105

Я пытался включить настраиваемые ошибки на производственном сервере в течение 3 часов, кажется, я нашел окончательное решение, как это сделать в ASP.NET MVC без каких-либо маршрутов.

Чтобы включить настраиваемые ошибки в приложении ASP.NET MVC, нам потребуется (IIS 7+):

  1. Настройте пользовательские страницы в веб-конфигурации в system.webразделе:

    <customErrors mode="RemoteOnly"  defaultRedirect="~/error">
        <error statusCode="404" redirect="~/error/Error404" />
        <error statusCode="500" redirect="~/error" />
    </customErrors>

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

  2. Установите параметр волшебного ответа и код состояния ответа (в модуле обработки ошибок или в атрибуте дескриптора ошибки)

      HttpContext.Current.Response.StatusCode = 500;
      HttpContext.Current.Response.TrySkipIisCustomErrors = true;
  3. Установите еще один волшебный параметр в веб-конфигурации в system.webServerразделе:

    <httpErrors errorMode="Detailed" />

Это было последнее, что я нашел, и после этого я могу видеть пользовательские ошибки на рабочем сервере.

Эндрю Орсич
источник
8
Это все еще не идеальное решение. Он не дает вам правильных кодов ответа HTTP. Использование customErrorsрезультатов в перенаправлении 302 только для загрузки страницы с ошибкой.
Джастин Хелгерсон
@ Ek0nomik Я никогда не видел идеальных решений :)
Эндрю Орсич
2
@JustinHelgerson Я настраиваю ErrorController для каждого кода состояния и устанавливаю коды ответа внутри этих действий, и он устанавливает правильные коды ответа. Я тестировал с Fiddler и кодами состояния 404 ответ 404, а страницы с 500 ошибками отвечают 500. И в обоих случаях обслуживаются мои пользовательские просмотры ошибок
Шейн Невилль
мой товарищ по команде только что удалил представление ошибок в общей папке, чтобы сделать ошибку времени выполнения с кодом состояния 500 для перенаправления на страницу пользовательской ошибки, как указано здесь и здесь . Надежда кому-то помогает.
Shaijut
41

Я заставил свою обработку ошибок работать, создав ErrorController, который возвращает представления в этой статье. Мне также пришлось добавить «Catch All» к маршруту в global.asax.

Я не вижу, как он попадет на любую из этих страниц с ошибками, если его нет в Web.config ..? Мой Web.config должен был указать:

customErrors mode="On" defaultRedirect="~/Error/Unknown"

а затем я также добавил:

error statusCode="404" redirect="~/Error/NotFound"
Джек Смит
источник
2
Спасибо, это помогло мне через 2 года! Что делать, если вам нужна только настраиваемая ошибка 404, и ничего больше?
Шауль Бер
1
@Shaul еще год спустя ... не устанавливайте defaultRedirect, полностью исключите атрибут.
NJE
27

Источник

NotFoundMVC - предоставляет удобную для пользователя страницу 404 всякий раз, когда контроллер, действие или маршрут не найдены в вашем приложении ASP.NET MVC3. Вместо страницы ошибок ASP.NET по умолчанию отображается представление NotFound.

Вы можете добавить этот плагин через nuget, используя: Install-Package NotFoundMvc

NotFoundMvc автоматически устанавливается при запуске веб-приложения. Он обрабатывает все различные способы, которыми ASP.NET MVC обычно генерирует исключение 404 HttpException. Это включает в себя отсутствующий контроллер, действие и маршрут.

Пошаговое руководство по установке:

1 - Щелкните правой кнопкой мыши свой проект и выберите "Управление пакетами Nuget" ...

2 - Найдите NotFoundMvcи установите. введите описание изображения здесь

3 - После завершения установки в ваш проект будут добавлены два файла. Как показано на скриншотах ниже.

введите описание изображения здесь

4 - Откройте только что добавленный NotFound.cshtml в папке Views / Shared и измените его по своему желанию. Теперь запустите приложение и введите неправильный URL-адрес, и вы увидите удобную для пользователя страницу 404.

введите описание изображения здесь

Нет, пользователи получат сообщение об ошибке, например Server Error in '/' Application. The resource cannot be found.

Надеюсь это поможет :)

PS: Спасибо Эндрю Дэйви за создание такого классного плагина.

Ясир Шейх
источник
@niico Судя по исходному коду, кажется, что код ответа установлен на 404, так что да.
Уилл Дин
20

Попробуйте это в web.config, чтобы заменить страницы ошибок IIS. Я думаю, это лучшее решение, и оно также отправляет правильный код состояния.

<system.webServer>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404" subStatusCode="-1" />
    <remove statusCode="500" subStatusCode="-1" />
    <error statusCode="404" path="Error404.html" responseMode="File" />
    <error statusCode="500" path="Error.html" responseMode="File" />
  </httpErrors>
</system.webServer>

Дополнительная информация от Tipila - Использование настраиваемых страниц ошибок ASP.NET MVC

Амила
источник
1
+1. Это единственное, что казалось мне стабильно работающим в MVC5 с несколькими областями.
hawkke
Это самое простое решение. Однако вы не можете использовать синтаксис бритвы на странице ошибки.
Highace
15

Это решение не требует изменений файла web.config или универсальных маршрутов.

Сначала создайте такой контроллер;

public class ErrorController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Title = "Regular Error";
        return View();
    }

    public ActionResult NotFound404()
    {
        ViewBag.Title = "Error 404 - File not Found";
        return View("Index");
    }
}

Затем создайте представление в «Views / Error / Index.cshtml» как;

 @{
      Layout = "~/Views/Shared/_Layout.cshtml";
  }                     
  <p>We're sorry, page you're looking for is, sadly, not here.</p>

Затем добавьте следующее в файл Global asax, как показано ниже:

protected void Application_Error(object sender, EventArgs e)
{
        // Do whatever you want to do with the error

        //Show the custom error page...
        Server.ClearError(); 
        var routeData = new RouteData();
        routeData.Values["controller"] = "Error";

        if ((Context.Server.GetLastError() is HttpException) && ((Context.Server.GetLastError() as HttpException).GetHttpCode() != 404))
        {
            routeData.Values["action"] = "Index";
        }
        else
        {
            // Handle 404 error and response code
            Response.StatusCode = 404;
            routeData.Values["action"] = "NotFound404";
        } 
        Response.TrySkipIisCustomErrors = true; // If you are using IIS7, have this line
        IController errorsController = new ErrorController();
        HttpContextWrapper wrapper = new HttpContextWrapper(Context);
        var rc = new System.Web.Routing.RequestContext(wrapper, routeData);
        errorsController.Execute(rc);

        Response.End();
}

Если после этого вы все еще получаете настраиваемую страницу ошибок IIS, убедитесь, что следующие разделы закомментированы (или пусты) в файле веб-конфигурации:

<system.web>
   <customErrors mode="Off" />
</system.web>
<system.webServer>   
   <httpErrors>     
   </httpErrors>
</system.webServer>
Sujeewa
источник
Я не думаю, что этот подход будет работать во всех случаях, поскольку 404-е сообщение часто перехватывается веб-сервером и поэтому никогда не обрабатывается на уровне приложения.
Крис Хэлкроу,
Я хочу добавить, что если вы воспользуетесь этим подходом, я бы рекомендовал добавить Response.End();в конец обработчика Application_Error. Без этого для данного сеанса запускается только первое возникновение ошибки, что является проблемой, когда у вас есть, например, настраиваемая регистрация ошибок в обработчике Application_Error.
Кейт
6

Если вы работаете в MVC 4, вы можете посмотреть это решение, у меня оно сработало.

Добавьте в мой следующий метод Application_Error Global.asax:

protected void Application_Error(object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    Server.ClearError();

    RouteData routeData = new RouteData();
    routeData.Values.Add("controller", "Error");
    routeData.Values.Add("action", "Index");
    routeData.Values.Add("exception", exception);

    if (exception.GetType() == typeof(HttpException))
    {
        routeData.Values.Add("statusCode", ((HttpException)exception).GetHttpCode());
    }
    else
    {
        routeData.Values.Add("statusCode", 500);
    }

    IController controller = new ErrorController();
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
    Response.End();

Сам контроллер действительно прост:

public class ErrorController : Controller
{
    public ActionResult Index(int statusCode, Exception exception)
    {
        Response.StatusCode = statusCode;
        return View();
    }
}

Проверьте полный исходный код Mvc4CustomErrorPage на GitHub .

Дык Хоанг
источник
0

У меня была та же проблема, что вам нужно сделать, это вместо добавления атрибута customErrors в файл web.config в папке Views вы должны добавить его в файл web.config в корневой папке ваших проектов.

SmokeIT
источник
0

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

Также работает в MVC 5.

Добавьте этот код в контроллер:

        if (bad) {
            Response.Clear();
            Response.TrySkipIisCustomErrors = true;
            Response.Write(product + I(" Toodet pole"));
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            //Response.ContentType = "text/html; charset=utf-8";
            Response.End();
            return null;
        }

На основе http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages

Андрус
источник
0

Я расскажу о некоторых конкретных случаях,

если вы используете метод PageNotFound в HomeController, как показано ниже

[Route("~/404")]
public ActionResult PageNotFound()
{
  return MyView();
}

это не сработает. Но вы должны очистить теги маршрута, как показано ниже,

//[Route("~/404")]
public ActionResult PageNotFound()
{
  return MyView();
}

И если вы измените его как имя метода в web.config, он будет работать. Однако не забудьте сделать код, как показано ниже, в web.config

<customErrors mode="On">
  <error statusCode="404" redirect="~/PageNotFound" /> 
 *// it is not "~/404" because it is not accepted url in Route Tag like [Route("404")]*
</customErrors>
Фуркан озтурк
источник