ASP.NET обработка ошибок MVC 404 [дубликат]

Возможные Дубликаты:
как я могу правильно обрабатывать 404 в ASP.NET MVC?

Я внес изменения, описанные в 404 обработчик ошибок Http в Asp.Net MVC (RC 5) и я все еще получаю стандартную страницу ошибки 404. Нужно ли что-то менять в IIS?

6 ответов


еще одно решение.

добавьте ErrorControllers или статическую страницу с информацией об ошибке 404.

изменить веб.config (в случае контроллера).

<system.web>
    <customErrors mode="On" >
       <error statusCode="404" redirect="~/Errors/Error404" />
    </customErrors>
</system.web>

или в случае статической страницы

<system.web>
    <customErrors mode="On" >
        <error statusCode="404" redirect="~/Static404.html" />
    </customErrors>
</system.web>

это будет обрабатывать как пропущенные маршруты, так и пропущенные действия.


я расследовал МНОГО о том, как правильно управлять 404s в MVC (в частности MVC3), и это, ИМХО-лучшее решение, которое я придумал:

в глобальном.асакс:

public class MvcApplication : HttpApplication
{
    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 404)
        {
            Response.Clear();

            var rd = new RouteData();
            rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
            rd.Values["controller"] = "Errors";
            rd.Values["action"] = "NotFound";

            IController c = new ErrorsController();
            c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
        }
    }
}

ErrorsController:

public sealed class ErrorsController : Controller
{
    public ActionResult NotFound()
    {
        ActionResult result;

        object model = Request.Url.PathAndQuery;

        if (!Request.IsAjaxRequest())
            result = View(model);
        else
            result = PartialView("_NotFound", model);

        return result;
    }
}

Edit:

если вы используете IoC( например, AutoFac), вы должны создать свой контроллер, используя:

var rc = new RequestContext(new HttpContextWrapper(Context), rd);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Errors");
c.Execute(rc);
из
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));

(необязательный)

объяснение:

есть 6 сценариев, которые я могу придумать, где ASP.NET MVC3 приложения могут генерировать 404s.

генерируется ASP.NET:

  • Сценарий 1: URL не соответствует маршруту в таблице маршрутов.

генерируется ASP.NET MVC:

  • вариант 2: URL соответствует a route, но указывает контроллер, который не существует.

  • Сценарий 3: URL соответствует маршруту, но указывает действие, которое не существует.

вручную сгенерирована:

  • сценарий 4: действие возвращает HttpNotFoundResult с помощью метода HttpNotFound ().

  • сценарий 5: действие вызывает HttpException со статусом код 404.

  • сценарий 6: действия вручную изменяют ответ.Свойство StatusCode до 404.

задачи

  • (A) показать пользовательскую страницу ошибки 404 пользователю.

  • (B) поддержите код состояния 404 на ответе клиента (специально важном для ОПТИМИЗАЦИЯ ПОИСКОВЫХ СИСТЕМ.)

  • (C) отправить ответ напрямую, без привлечения перенаправления 302.

Попытка Решения: Пользовательские Ошибки

<system.web>
    <customErrors mode="On">
        <error statusCode="404" redirect="~/Errors/NotFound"/>
    </customError>
</system.web>

проблемы с этим решением:

  • не соответствует цели (A) в сценариях (1), (4), (6).
  • не соответствует цели (B) автоматически. Он должен быть запрограммирован вручную.
  • не соответствует требованиям с цели (с).

попытка решения: ошибки HTTP

<system.webServer>
    <httpErrors errorMode="Custom">
        <remove statusCode="404"/>
        <error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

проблемы с этим решением:

  • работает только на IIS 7+.
  • не соответствует цели (A) в сценариях (2), (3), (5).
  • не соответствует цели (B) автоматически. Он должен быть запрограммирован вручную.

попытка решения: ошибки HTTP с Заменить

<system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace">
        <remove statusCode="404"/>
        <error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

проблемы с этим решением:

  • работает только на IIS 7+.
  • не соответствует цели (B) автоматически. Он должен быть запрограммирован вручную.
  • он скрывает исключения http уровня приложения. Е. Г. не могу использовать параметр customerrors раздел, системы.Сеть.В MVC.HandleErrorAttribute, и т. д. Он не может показывать только общие страницы ошибок.

попытка решения customErrors и HTTP Ошибки

<system.web>
    <customErrors mode="On">
        <error statusCode="404" redirect="~/Errors/NotFound"/>
    </customError>
</system.web>

и

<system.webServer>
    <httpErrors errorMode="Custom">
        <remove statusCode="404"/>
        <error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

проблемы с этим решением:

  • работает только на IIS 7+.
  • не соответствует цели (B) автоматически. Он должен быть запрограммирован вручную.
  • не соответствует цели (C) в сценариях (2), (3), (5).

люди, которые беспокоились об этом, прежде чем даже пытались создать свои собственные библиотеки (см. http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html). Но предыдущее решение, похоже, охватывает все сценарии без сложности использования внешней библиотеки.


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

вот окончательный код, который я использую:

protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 404)
        {
            var exception = Server.GetLastError();
            var httpException = exception as HttpException;
            Response.Clear();
            Server.ClearError();
            var routeData = new RouteData();
            routeData.Values["controller"] = "ErrorManager";
            routeData.Values["action"] = "Fire404Error";
            routeData.Values["exception"] = exception;
            Response.StatusCode = 500;

            if (httpException != null)
            {
                Response.StatusCode = httpException.GetHttpCode();
                switch (Response.StatusCode)
                {
                    case 404:
                        routeData.Values["action"] = "Fire404Error";
                        break;
                }
            }
            // Avoid IIS7 getting in the middle
            Response.TrySkipIisCustomErrors = true;
            IController errormanagerController = new ErrorManagerController();
            HttpContextWrapper wrapper = new HttpContextWrapper(Context);
            var rc = new RequestContext(wrapper, routeData);
            errormanagerController.Execute(rc);
        }
    }

и внутри моего ErrorManagerController :

        public void Fire404Error(HttpException exception)
    {
        //you can place any other error handling code here
        throw new PageNotFoundException("page or resource");
    }

Теперь, в моем действии, я бросаю Пользовательское исключение, которое я создал. И мой контроллер наследует от пользовательского класса на основе контроллера, который я создал. Пользовательский базовый контроллер был создан для переопределения обработки ошибок. Вот мой пользовательский базовый класс:

public class MyBasePageController : Controller
{
    protected override void OnException(ExceptionContext filterContext)
    {
        filterContext.GetType();
        filterContext.ExceptionHandled = true;
        this.View("ErrorManager", filterContext).ExecuteResult(this.ControllerContext);
        base.OnException(filterContext);
    }
}

"ErrorManager" в приведенном выше коде-это просто представление, которое использует модель, основанную на ExceptionContext

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


похоже, это лучший способ поймать все.

как я могу правильно обрабатывать 404 в ASP.NET MVC?


Что я могу рекомендовать, это посмотреть на FilterAttribute. Например, MVC уже имеет HandleErrorAttribute. Вы можете настроить его для обработки только 404. Ответ если вы interesed я пример смотрите.

кстати

решение (с последним маршрутом), которое вы приняли в предыдущем вопросе, не работает во многих ситуациях. Второе решение с HandleUnknownAction будет работать, но требует, чтобы сделать это изменение в каждом контроллере или иметь одну базу контроллер.

мой выбор-это решение с HandleUnknownAction.


в IIS вы можете указать перенаправление на" определенную " страницу на основе кода ошибки. В примере вы можете настроить 404 - > настроенную страницу ошибки 404.