Routing dla niestandardowej strony błędu 404 ASP.NET MVC

116

Próbuję utworzyć niestandardową stronę błędu HTTP 404, gdy ktoś wpisze adres URL, który nie wywołuje prawidłowej akcji lub kontrolera w ASP.NET MVC, zamiast wyświetlać ogólny błąd ASP.NET „Nie znaleziono zasobu”.

Nie chcę do tego celu używać pliku web.config.

Czy jest jakaś magia routingu, którą mogę zrobić, aby złapać nieprawidłowe adresy URL?

Aktualizacja: wypróbowałem udzieloną odpowiedź, ale nadal otrzymuję brzydki komunikat „Nie znaleziono zasobu”.

Kolejna aktualizacja: Ok, podobno coś się zmieniło w RC1. Próbowałem nawet specjalnie przechwytywać 404 na an HttpExceptioni nadal wyświetla mi się strona „Nie znaleziono zasobu”.

Użyłem nawet funkcji zasobów MvcContrib i nic - ten sam problem. Jakieś pomysły?

dswatik
źródło
@Peter To jest rozwiązanie, które dodałem, wraz z przesłonięciem HandleUnknownAction, aby wyświetlić widok strony nie znaleziono, gdy akcja nie istnieje, a następnie wbudowany w ASP.net niestandardowy program obsługi błędów, który obsługuje wszystko inne niewygodne, które użytkownicy mogą wpisać ,
dswatik
@pete To działa również stackoverflow.com/questions/619895/ ...
dswatik
8
Nienawidzę, gdy inni użytkownicy są zarozumiali i mówią takie rzeczy jak „dlaczego chcesz to zrobić? Po prostu zrób to…”. Ale sugerowałbym, że jeśli nic nie powstrzymuje Cię przed użyciem podejścia web.config zaspokoi Twoje potrzeby, to standardowe i eleganckie podejście. Wszelkie uwagi na temat tego podejścia są mile widziane, ponieważ bardzo dobrze może być z nim problem, o którym nie wiem.
Sean

Odpowiedzi:

10

Po prostu dodaj złap całą trasę na końcu tabeli tras i wyświetl na niej dowolną stronę.

Zobacz: Jak utworzyć trasę przechwytującą wszystkie, aby obsłużyć zapytania „Nie znaleziono strony 404” dla ASP.NET MVC?

Alex Reitbort
źródło
Próbowałem tego jednak, nadal otrzymuję brzydki domyślny komunikat o
nieznalezieniu
3
Nie znajduję ostatecznego (i elastycznego !!) rozwiązania tego problemu ani w tej odpowiedzi, ani w podanym linku.
Peter
4
Ja też nie ... wydaje się, że to trochę zepsuta odpowiedź. Szukam bardziej sposobu, aby customErrors zachowywał się tak, jak robią to w WebForms. Jakieś pomysły?
JC Grubbs
1
To nie działa i jest z zasady złe. Nie działa, ponieważ nie przechwytuje złych adresów URL, które pasują do jednego z wcześniejszych wzorców routingu. Złe z zasady, ponieważ zamienia to, co powinno być błędem, w nie błąd. Przekierowywanie do strony o nazwie „Błąd” różni się od przekierowywania do strony błędu. Chcesz zachować to jako błąd, zarejestruj go, a następnie potraktuj go jako błąd. Błędy to cenne informacje.
Matthew
105

Próbowałem włączyć niestandardowe błędy na serwerze produkcyjnym przez 3 godziny, wydaje się, że znalazłem ostateczne rozwiązanie, jak to zrobić w ASP.NET MVC bez żadnych tras.

Aby włączyć niestandardowe błędy w aplikacji ASP.NET MVC, potrzebujemy (IIS 7+):

  1. Skonfiguruj niestandardowe strony w konfiguracji internetowej w system.websekcji:

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

    RemoteOnlyoznacza, że ​​w sieci lokalnej zobaczysz prawdziwe błędy (bardzo przydatne podczas programowania). Możemy również przepisać stronę błędu dla dowolnego kodu błędu.

  2. Ustaw parametr Magic Response i kod statusu odpowiedzi (w module obsługi błędów lub w atrybucie uchwytu błędu)

      HttpContext.Current.Response.StatusCode = 500;
      HttpContext.Current.Response.TrySkipIisCustomErrors = true;
    
  3. Ustaw kolejne magiczne ustawienie w konfiguracji internetowej w system.webServersekcji:

    <httpErrors errorMode="Detailed" />

To była ostatnia rzecz, jaką znalazłem i po tym widzę niestandardowe błędy na serwerze produkcyjnym.

Andrew Orsich
źródło
8
To wciąż nie jest idealne rozwiązanie. Nie zapewnia poprawnych kodów odpowiedzi HTTP. Korzystanie z customErrorswyników w przekierowaniu 302 tylko w celu załadowania strony błędu.
Justin Helgerson
@ Ek0nomik Nigdy nie widziałem idealnych rozwiązań :)
Andrew Orsich
2
@JustinHelgerson Ustawiam ErrorController dla każdego kodu statusu i ustawiam kody odpowiedzi wewnątrz tych akcji i ustawia kody odpowiedzi dobrze. Testowałem z Fiddlerem i 404 kody statusu odpowiadały 404, a strony z błędami 500 odpowiadały 500. I w obu przypadkach moje niestandardowe widoki błędów są wyświetlane
Shane Neuville,
mój kolega z zespołu właśnie usunął widok błędów w folderze współdzielonym , aby spowodować błąd w czasie wykonywania z kodem statusu 500 w celu przekierowania do niestandardowej strony błędu, jak wspomniano tutaj i tutaj . Nadzieja pomaga komuś.
shaijut
41

Mam obsługę błędów do pracy, tworząc ErrorController, który zwraca widoki w tym artykule. Musiałem również dodać „Catch All” do trasy w global.asax.

Nie widzę, jak dotrze do którejkolwiek z tych stron błędów, jeśli nie ma jej w pliku Web.config ..? Mój Web.config musiał określić:

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

a potem dodałem też:

error statusCode="404" redirect="~/Error/NotFound"
Jack Smit
źródło
2
Dzięki - to mi pomogło, 2 lata później! Co zrobić, jeśli chcesz tylko niestandardowego błędu 404, nic więcej?
Shaul Behr
1
@Shaul kolejny rok później ... nie ustawiaj defaultRedirect, całkowicie wyklucz atrybut.
NJE
27

Źródło

NotFoundMVC - zapewnia przyjazną dla użytkownika stronę 404 za każdym razem, gdy kontroler, akcja lub trasa nie zostanie znaleziona w aplikacji ASP.NET MVC3. Widok o nazwie NotFound jest renderowany zamiast domyślnej strony błędu ASP.NET.

Możesz dodać tę wtyczkę za pośrednictwem nuget przy użyciu: Install-Package NotFoundMvc

NotFoundMvc instaluje się automatycznie podczas uruchamiania aplikacji internetowej. Obsługuje wszystkie różne sposoby, w jakie 404 HttpException jest zwykle generowane przez ASP.NET MVC. Obejmuje to brakujący kontroler, akcję i trasę.

Instrukcja instalacji krok po kroku:

1 - Kliknij prawym przyciskiem myszy swój projekt i wybierz Zarządzaj pakietami Nuget ...

2 - Wyszukaj NotFoundMvci zainstaluj. wprowadź opis obrazu tutaj

3 - Po zakończeniu instalacji do projektu zostaną dodane dwa pliki. Jak pokazano na poniższych zrzutach ekranu.

wprowadź opis obrazu tutaj

4 - Otwórz nowo dodany plik NotFound.cshtml obecny w Views / Shared i zmodyfikuj go według własnego uznania. Teraz uruchom aplikację i wpisz nieprawidłowy adres URL, a zostaniesz powitany przyjazną dla użytkownika stroną 404.

wprowadź opis obrazu tutaj

Nigdy więcej, użytkownicy otrzymają komunikat o błędzie, taki jak Server Error in '/' Application. The resource cannot be found.

Mam nadzieję że to pomoże :)

PS: Wyrazy uznania dla Andrew Davey za zrobienie tak niesamowitej wtyczki.

Yasser Shaikh
źródło
@niico Patrząc na kod źródłowy wydaje się, że ustawiono kod odpowiedzi na 404, więc tak.
Will Dean,
20

Spróbuj tego w pliku web.config, aby zastąpić strony błędów usług IIS. To chyba najlepsze rozwiązanie, które wysyła również prawidłowy kod statusu.

<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>

Więcej informacji od Tipila - Użyj niestandardowych stron błędów ASP.NET MVC

Amila
źródło
1
+1. To jedyna rzecz, która wydawała mi się działać konsekwentnie na MVC5 z wieloma obszarami.
hawkke
To najłatwiejsze rozwiązanie. Nie możesz jednak używać składni maszynki do golenia na stronie błędu.
highace
15

To rozwiązanie nie wymaga zmian w pliku web.config ani tras typu catch-all.

Najpierw utwórz taki kontroler;

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

Następnie utwórz widok w „Views / Error / Index.cshtml” jako;

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

Następnie dodaj następujące elementy w pliku Global asax, jak poniżej:

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

Jeśli po wykonaniu tej czynności nadal pojawia się niestandardowa strona błędu usług IIS, upewnij się, że następujące sekcje są zakomentowane (lub puste) w pliku konfiguracji sieci Web:

<system.web>
   <customErrors mode="Off" />
</system.web>
<system.webServer>   
   <httpErrors>     
   </httpErrors>
</system.webServer>
Sujeewa
źródło
Nie sądzę, aby to podejście zadziałało we wszystkich przypadkach, ponieważ 404 jest często przechwytywane przez serwer sieciowy i dlatego nigdy nie jest obsługiwane na poziomie aplikacji.
Chris Halcrow,
Chcę dodać, że jeśli zdecydujesz się na to podejście, polecam dodanie Response.End();na końcu programu obsługi Application_Error. Bez tego wyzwalane jest tylko pierwsze wystąpienie błędu dla danej sesji, co jest problemem w przypadku np. Niestandardowego logowania błędów w module obsługi Application_Error.
Keith
6

Jeśli pracujesz w MVC 4, możesz obejrzeć to rozwiązanie, u mnie zadziałało.

Dodaj następującą metodę Application_Error do my 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();

Sam kontroler jest naprawdę prosty:

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

Sprawdź pełny kod źródłowy Mvc4CustomErrorPage na GitHub .

Duc Hoang
źródło
0

Miałem ten sam problem, co musisz zrobić, to zamiast dodawać atrybut customErrors do pliku web.config w folderze Views, musisz dodać go do pliku web.config w katalogu głównym projektów

Zapal to
źródło
0

Oto prawdziwa odpowiedź, która pozwala w pełni dostosować stronę błędu w jednym miejscu. Nie ma potrzeby modyfikowania pliku web.config ani tworzenia oddzielnego kodu.

Działa również w MVC 5.

Dodaj ten kod do kontrolera:

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

Na podstawie http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages

Andrus
źródło
0

Opowiem o kilku konkretnych przypadkach,

jeśli używasz „metody PageNotFound” w HomeController, jak poniżej

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

to by nie zadziałało. Ale musisz wyczyścić tagi trasy, jak poniżej,

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

A jeśli zmienisz to jako nazwę metody w pliku web.config, to działa. Nie zapomnij jednak zrobić kodu jak poniżej w 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>
Furkan ozturk
źródło