ASP.NET obsługa błędów MVC 404 [duplikat]

Możliwy duplikat:
Jak prawidłowo obsłużyć 404 w ASP.NET MVC?

Wprowadziłem zmiany opisane w 404 HTTP Error handler w Asp.Net MVC (RC 5) i nadal dostaję standardową stronę błędu 404. Czy muszę coś zmienić w IIS?

Author: Community, 2009-04-04

6 answers

Jeszcze jedno rozwiązanie.

Dodaj ErrorControllers lub statyczną stronę do informacji o błędzie 404.

Modify you web.config (w przypadku kontrolera).

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

Lub w przypadku strony statycznej

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

Będzie to obsługiwać zarówno nieodebrane trasy, jak i nieodebrane działania.

 136
Author: Mike Chaliy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-25 23:50:05

Badałem wiele Jak prawidłowo zarządzać 404s w MVC (konkretnie MVC3) , i to, IMHO jest najlepszym rozwiązaniem, jakie wymyśliłem:

In global.asax:

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:

Jeśli używasz IoC (np. AutoFac), powinieneś utworzyć swój kontroler używając:

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

Zamiast

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

(Opcjonalnie)

Explanation:

Jest 6 scenariusze, które mogę wymyślić, gdzie ASP.NET aplikacje MVC3 mogą generować 404s.

Wygenerowane przez ASP.NET:

  • scenariusz 1: URL nie pasuje do trasy w tabeli tras.

Wygenerowane przez ASP.NET MVC:

  • Scenariusz 2: URL pasuje do trasy, ale określa kontroler, który nie istnieje.

  • Scenariusz 3: URL pasuje do trasy, ale określa akcję, która nie istnieć.

Wygenerowano ręcznie:

  • Scenariusz 4: akcja zwraca HttpNotFoundResult przy użyciu metody HttpNotFound().

  • Scenariusz 5: akcja wyświetla HttpException z kodem stanu 404.

  • Scenariusz 6: akcja ręcznie modyfikuje odpowiedź.Właściwość StatusCode do 404.

Cele

  • (A) Pokaż a niestandardowa strona błędu 404 dla użytkownika.

  • (B) Zachowaj kod statusu 404 w Odpowiedzi klienta (szczególnie ważny dla SEO).

  • (C) wyślij odpowiedź bezpośrednio, bez angażowania przekierowania 302.

Próba Rozwiązania: Błędy Niestandardowe

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

Problemy z tym rozwiązaniem:

  • nie spełnia celu (a) w scenariuszach (1), (4), (6).
  • nie spełnia cel (B) automatycznie. Musi być zaprogramowany ręcznie.
  • nie jest zgodny z celem (C).

Próba rozwiązania: błędy HTTP

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

Problemy z tym rozwiązaniem:

  • działa tylko na IIS 7+.
  • nie spełnia celu (a) w scenariuszach (2), (3), (5).
  • nie spełnia automatycznie celu (B). Musi być zaprogramowany ręcznie.

Próba rozwiązania: błędy HTTP z Zastąp

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

Problemy z tym rozwiązaniem:

  • działa tylko na IIS 7+.
  • nie spełnia automatycznie celu (B). Musi być zaprogramowany ręcznie.
  • zasłania wyjątki http na poziomie aplikacji. Np. nie można użyć sekcji customErrors, System.Www.Mvc.HandleErrorAttribute itp. Nie może wyświetlać tylko ogólnych stron błędów.

Rozwiązanie próby customErrors i HTTP Błędy

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

I

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

Problemy z tym rozwiązaniem:

  • działa tylko na IIS 7+.
  • nie spełnia automatycznie celu (B). Musi być zaprogramowany ręcznie.
  • nie spełnia celu (C) w scenariuszach (2), (3), (5).

Ludzie, którzy mieli z tym problem, próbowali nawet stworzyć własne biblioteki (zobacz http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html ). ale poprzednie rozwiązanie wydaje się obejmować wszystkie scenariusze bez złożoności korzystania z zewnętrznej biblioteki.

 353
Author: Marco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-18 15:27:55

Odpowiedź Marco jest najlepszym rozwiązaniem. Musiałem kontrolować moją obsługę błędów, i mam na myśli naprawdę kontrolować to. Oczywiście trochę rozszerzyłem rozwiązanie i stworzyłem pełny system zarządzania błędami, który zarządza wszystkim. Czytałem również o tym rozwiązaniu na innych blogach i wydaje się bardzo akceptowalne przez większość zaawansowanych programistów.

Oto ostateczny kod, którego używam:

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);
        }
    }

I w moim ErrorManagerController :

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

Teraz, w moim Akcja, rzucam Niestandardowy wyjątek, który stworzyłem. A mój Kontroler dziedziczy po stworzonej przeze mnie niestandardowej klasie opartej na kontrolerze. Niestandardowy Kontroler bazowy został stworzony w celu obejścia obsługi błędów. Oto moja klasa kontrolera bazowego:

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" w powyższym kodzie jest tylko widokiem używającym modelu opartego na ExceptionContext

Moje rozwiązanie działa doskonale i jestem w stanie obsłużyć każdy błąd na mojej stronie i wyświetlać różne komunikaty na podstawie dowolnego typu wyjątku.

 5
Author: Yousi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-11 13:03:02

Wygląda na to, że to najlepszy sposób na złapanie wszystkiego.

Jak prawidłowo obsłużyć 404 w ASP.NET MVC?

 4
Author: Clearly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:31

To, co mogę polecić, to spojrzeć na FilterAttribute. Na przykład MVC ma już HandleErrorAttribute. Możesz dostosować go do obsługi tylko 404. Odpowiedz, jeśli jesteś zainteresowany, poszukam przykładu.

BTW

Rozwiązanie (z ostatnią trasą), które zaakceptowałeś w poprzednim pytaniu, nie działa w większości sytuacji. Drugie rozwiązanie z HandleUnknownAction będzie działać, ale wymaga wprowadzenia tej zmiany w każdym kontrolerze lub posiadania jednego kontrolera bazowego.

My wybór jest rozwiązaniem z HandleUnknownAction.

 1
Author: Mike Chaliy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-05 15:28:20

W IIS możesz określić przekierowanie do "pewnej" strony na podstawie kodu błędu. W twoim przykładzie możesz skonfigurować 404 - > dostosowaną stronę błędu 404.

 0
Author: J.W.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-04 19:33:16