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

Używam RC2

Korzystanie z adresu URL:

routes.MapRoute(
    "Error",
     "{*url}",
     new { controller = "Errors", action = "NotFound" }  // 404s
);

Powyższe wydaje się dbać o takie żądania (zakładając domyślne tabele tras ustawione przez początkowy projekt MVC): "/ bla / bla/bla / bla"

Nadpisanie funkcji HandleUnknownAction () w samym kontrolerze:

// 404s - handle here (bad action requested
protected override void HandleUnknownAction(string actionName) {
    ViewData["actionName"] = actionName;
    View("NotFound").ExecuteResult(this.ControllerContext);
}  

Jednak poprzednie strategie nie obsługują żądania do złego / nieznanego kontrolera. Na przykład nie mam "/ IDoNotExist", jeśli o to poproszę, dostaję ogólną stronę 404 z serwer WWW, a nie mój 404 Jeśli używam routingu + override.

Więc na koniec moje pytanie brzmi: Czy Jest jakiś sposób, aby złapać tego typu żądania za pomocą trasy lub czegoś innego w samym frameworku MVC?

Czy powinienem domyślnie używać Web.Config customErrors jako mój handler 404 i zapomnieć o tym wszystkim? Zakładam, że jeśli pójdę z customErrors będę musiał przechowywać ogólną stronę 404 poza / Views ze względu na sieć.Ograniczenia konfiguracji bezpośredniego dostępu.

Author: Flimzy, 2009-03-06

19 answers

Kod pochodzi z http://blogs.microsoft.co.il/blogs/shay/archive/2009/03/06/real-world-error-hadnling-in-asp-net-mvc-rc2.aspx{[3]i pracuje w ASP.net MVC 1.0 również

Oto jak obsługuję wyjątki http:

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

   ILogger logger = Container.Resolve<ILogger>();
   logger.Error(exception);

   Response.Clear();

   HttpException httpException = exception as HttpException;

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

   if (httpException == null)
   {
       routeData.Values.Add("action", "Index");
   }
   else //It's an Http Exception, Let's handle it.
   {
       switch (httpException.GetHttpCode())
       {
          case 404:
              // Page not found.
              routeData.Values.Add("action", "HttpError404");
              break;
          case 500:
              // Server error.
              routeData.Values.Add("action", "HttpError500");
              break;

           // Here you can handle Views to other error codes.
           // I choose a General error template  
           default:
              routeData.Values.Add("action", "General");
              break;
      }
  }           

  // Pass exception details to the target error View.
  routeData.Values.Add("error", exception);

  // Clear the error on server.
  Server.ClearError();

  // Avoid IIS7 getting in the middle
  Response.TrySkipIisCustomErrors = true; 

  // Call target Controller and pass the routeData.
  IController errorController = new ErrorController();
  errorController.Execute(new RequestContext(    
       new HttpContextWrapper(Context), routeData));
}
 253
Author: Shay Jacoby,
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
2010-10-05 18:17:30

Wymagania dla 404

Oto moje wymagania dla rozwiązania 404, a poniżej pokazuję, jak je wdrażam:

  • chcę obsługiwać dopasowane trasy z złych działań
  • chcę obsługiwać dopasowane trasy ze złymi kontrolerami
  • chcę obsługiwać Nie dopasowane trasy (arbitralne adresy URL, których moja aplikacja nie może zrozumieć) - nie chcę, aby te bąbelki do globalnego.asax lub IIS ponieważ wtedy Nie mogę przekierować z powrotem do mojej aplikacji MVC właściwie
  • chcę, aby Sposób obsługi w taki sam sposób, jak powyżej, niestandardowe 404s-jak wtedy, gdy identyfikator jest przesyłany dla obiektu, który nie istnieje (może usunięty)
  • chcę, aby wszystkie moje 404 zwracały widok MVC (nie statyczną stronę), do którego mogę później pompować więcej danych, jeśli to konieczne ( dobre projekty 404) i oni muszą zwrócić kod statusu HTTP 404

Rozwiązanie

Myślę, że powinieneś zapisać Application_Error w globalnym.asax dla wyższych rzeczy, takie jak nieobsługiwane wyjątki i logowanie (jak Shay Jacoby ' s answer pokazuje), ale nie obsługa 404. Dlatego moja sugestia trzyma 404 rzeczy z dala od globalnego.plik asax.

Krok 1: miej wspólne miejsce dla 404-logika błędów

Jest to dobry pomysł na konserwację. Użyj ErrorController , aby przyszłe ulepszenia do Twojej dobrze zaprojektowanej strony 404 mogły się łatwo dostosować. upewnij się, że Twoja odpowiedź ma 404 kod !

public class ErrorController : MyController
{
    #region Http404

    public ActionResult Http404(string url)
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        var model = new NotFoundViewModel();
        // If the url is relative ('NotFound' route) then replace with Requested path
        model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ?
            Request.Url.OriginalString : url;
        // Dont get the user stuck in a 'retry loop' by
        // allowing the Referrer to be the same as the Request
        model.ReferrerUrl = Request.UrlReferrer != null &&
            Request.UrlReferrer.OriginalString != model.RequestedUrl ?
            Request.UrlReferrer.OriginalString : null;

        // TODO: insert ILogger here

        return View("NotFound", model);
    }
    public class NotFoundViewModel
    {
        public string RequestedUrl { get; set; }
        public string ReferrerUrl { get; set; }
    }

    #endregion
}

Krok 2: Użyj podstawowej klasy kontrolera, aby łatwo wywołać niestandardową akcję 404 i podłączyć ją HandleUnknownAction

404s w ASP.NET MVC muszą być złowione w wielu miejscach. Pierwszy to HandleUnknownAction.

Metoda InvokeHttp404 tworzy wspólne miejsce dla przekierowania do ErrorController i naszej nowej akcji Http404. Pomyśl wytrzyj !

public abstract class MyController : Controller
{
    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        // If controller is ErrorController dont 'nest' exceptions
        if (this.GetType() != typeof(ErrorController))
            this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}
Krok 3: Użyj Dependency Injection w fabryce kontrolera i podłącz 404 HttpExceptions]}

Like so (it nie musi być StructureMap):

przykład MVC1. 0:

public class StructureMapControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(controllerType);
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
            {
                IController errorController = ObjectFactory.GetInstance<ErrorController>();
                ((ErrorController)errorController).InvokeHttp404(RequestContext.HttpContext);

                return errorController;
            }
            else
                throw ex;
        }

        return ObjectFactory.GetInstance(controllerType) as Controller;
    }
}

przykład MVC2. 0:

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(requestContext, controllerType);
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == 404)
            {
                IController errorController = ObjectFactory.GetInstance<ErrorController>();
                ((ErrorController)errorController).InvokeHttp404(requestContext.HttpContext);

                return errorController;
            }
            else
                throw ex;
        }

        return ObjectFactory.GetInstance(controllerType) as Controller;
    }

Myślę, że lepiej jest łapać błędy bliżej miejsca ich powstania. Dlatego wolę powyższe od Application_Error.

To drugie miejsce, gdzie można złapać 404.]}

Krok 4: Dodaj NotFound route do Global.asax dla adresów URL, które nie są przetwarzane w aplikacji

Ta trasa powinna wskazywać na naszą Http404 akcję. Zwróć uwagę na url param będzie względnym adresem URL, ponieważ silnik routingu usuwa część domeny tutaj? Dlatego mamy całą tę warunkową logikę url w Kroku 1.

        routes.MapRoute("NotFound", "{*url}", 
            new { controller = "Error", action = "Http404" });

To trzecie i ostatnie miejsce, aby złapać 404s w aplikacji MVC, że nie powoływać się. Jeśli nie złapiesz tu niezrównanych tras, MVC przekaże problem do ASP.NET (Global.asax) i tak naprawdę nie chcesz tego w tej sytuacji.

Krok 5: na koniec wywołaj 404s, gdy aplikacja nie może znaleźć coś

Jak wtedy, gdy zły identyfikator jest złożony do mojego kontrolera kredytów (wynika z MyController):

    //
    // GET: /Detail/ID

    public ActionResult Detail(int ID)
    {
        Loan loan = this._svc.GetLoans().WithID(ID);
        if (loan == null)
            return this.InvokeHttp404(HttpContext);
        else
            return View(loan);
    }

Byłoby miło, gdyby to wszystko można było podłączyć w mniejszej liczbie miejsc z mniejszą ilością kodu, ale myślę, że to rozwiązanie jest bardziej łatwe do utrzymania, bardziej testowalne i dość pragmatyczne.

Dzięki za opinie na razie. Chciałbym dostać więcej.

Uwaga: to zostało edytowane znacznie z mojej oryginalnej odpowiedzi, ale cel/wymagania są takie same - dlatego ja nie dodano nowej odpowiedzi

 251
Author: Matt Kocaj,
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:35

ASP.NET MVC nie obsługuje niestandardowych stron 404 bardzo dobrze. Custom Controller factory, catch-all route, base controller class with HandleUnknownAction - argh!

Niestandardowe strony błędów IIS są na razie lepszą alternatywą:

Www.config

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

ErrorController

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View();
    }
}

Przykładowy Projekt

 225
Author: Pavel Chuchuva,
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
2015-05-04 07:28:52

Szybka Odpowiedź / TL; DR

Tutaj wpisz opis obrazka

Dla leniwych ludzi:

Install-Package MagicalUnicornMvcErrorToolkit -Version 1.0

Następnie usuń ten wiersz z global.asax

GlobalFilters.Filters.Add(new HandleErrorAttribute());

i to jest tylko dla IIS7 + i IIS Express.

Jeśli używasz Cassini .. cóż .. um .. er.. niezręcznie ... niezręczne

Długa, wyjaśniona odpowiedź

Wiem, że ktoś na to odpowiedział. Ale odpowiedź jest naprawdę prosta (Pozdro Dla Davida Fowlera i Damiana Edwardsa dla naprawdę odpowiedź na to pytanie).

Nie ma potrzeby robić niczego niestandardowego .

Dla ASP.NET MVC3, wszystkie kawałki i kawałki są tam.

Krok 1 - > zaktualizuj swoją sieć.config w dwóch miejscach.

<system.web>
    <customErrors mode="On" defaultRedirect="/ServerError">
      <error statusCode="404" redirect="/NotFound" />
    </customErrors>

I

<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404" subStatusCode="-1" />
      <error statusCode="404" path="/NotFound" responseMode="ExecuteURL" />
      <remove statusCode="500" subStatusCode="-1" />
      <error statusCode="500" path="/ServerError" responseMode="ExecuteURL" />
    </httpErrors>    

...
<system.webServer>
...
</system.web>
Teraz zwróć uwagę na trasy, z których zdecydowałem się skorzystać. Możesz użyć wszystkiego, ale Moje trasy to
  • /NotFound
  • /ServerError

Widzisz jak pierwsza sekcja w <system.web> ma tylko jeden Niestandardowy wpis? statusCode="404" wpis? Wymieniłem tylko jeden kod statusu, ponieważ wszystkie inne błędy, w tym 500 Server Error (ie. te brzydkie błąd, który dzieje się, gdy kod ma błąd i zawiesza żądanie użytkownika).. wszystkie pozostałe błędy są obsługiwane przez ustawienie defaultRedirect="/ServerError".. co mówi, jeśli nie jesteś 404 Strona nie znaleziono, następnie proszę goto trasy /ServerError.

Ok. to z drogi.. teraz do moich tras wymienionych w global.asax

Krok 2-tworzenie tras w trybie globalnym.asax

Oto mój pełny odcinek trasy..
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.IgnoreRoute("{*favicon}", new {favicon = @"(.*/)?favicon.ico(/.*)?"});

    routes.MapRoute(
        "Error - 404",
        "NotFound",
        new { controller = "Error", action = "NotFound" }
        );

    routes.MapRoute(
        "Error - 500",
        "ServerError",
        new { controller = "Error", action = "ServerError"}
        );

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new {controller = "Home", action = "Index", id = UrlParameter.Optional}
        );
}

Który wymienia dwie ignorowane trasy - > axd's i favicons (ooo! bonus dla Ciebie!) Następnie (a kolejność jest tu niezbędna), mam moje dwa wyraźne trasy obsługi błędów .. a następnie innymi trasami. W tym przypadku domyślnym. Oczywiście, mam więcej, ale to jest specjalne dla mojej strony internetowej. tylko upewnij się, że trasy błędów są na na szczycie listy. Porządek jest konieczny .

Wreszcie, gdy znajdujemy się w naszym pliku global.asax, nie rejestrujemy globalnie atrybutu HandleError. Nie, Nie, Nie sir. Nadda. Nie. Nien. Nie. Nieeee...

Usuń ten wiersz z global.asax

GlobalFilters.Filters.Add(new HandleErrorAttribute());

Krok 3-Utwórz kontroler z metodami akcji

Teraz .. dodajemy kontroler z dwiema metodami akcji ...
public class ErrorController : Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View();
    }

    public ActionResult ServerError()
    {
        Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        // Todo: Pass the exception into the view model, which you can make.
        //       That's an exercise, dear reader, for -you-.
        //       In case u want to pass it to the view, if you're admin, etc.
        // if (User.IsAdmin) // <-- I just made that up :) U get the idea...
        // {
        //     var exception = Server.GetLastError();
        //     // etc..
        // }

        return View();
    }

    // Shhh .. secret test method .. ooOOooOooOOOooohhhhhhhh
    public ActionResult ThrowError()
    {
        throw new NotImplementedException("Pew ^ Pew");
    }
}
Ok, sprawdźmy to. Po pierwsze, nie ma nie [HandleError] atrybut tutaj. Dlaczego? Ponieważ wbudowany framework ASP.NET już obsługuje błędy i określiliśmy wszystko, co musimy zrobić, aby obsłużyć błąd :) to w tej metodzie!

Następnie mam dwie metody działania. Nic trudnego. Jeśli chcesz wyświetlić informacje o wyjątkach, możesz użyć Server.GetLastError(), aby uzyskać te informacje.

Bonus WTF: tak, zrobiłem trzecią metodę działania, aby przetestować obsługę błędów.

Krok 4-Utwórz widoki

I na koniec utwórz dwa widoki. Put em w normalnym miejscu widoku, dla tego kontrolera.

Tutaj wpisz opis obrazka

Komentarze bonusowe

  • nie potrzebujesz Application_Error(object sender, EventArgs e)
  • wszystkie powyższe kroki działają w 100% idealnie z Elmah . Elmah pieprzone wroxs!
I to, moi przyjaciele, powinno być to.

Gratulacje za przeczytanie tego dużo i mieć jednorożca jako nagrodę!

Tutaj wpisz opis obrazka

 153
Author: Pure.Krome,
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 12:10:41

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

(opcjonalnie)

Explanation:

AFAIK, jest 6 różnych przypadków, które ASP.NET aplikacje MVC3 mogą generować 404s.

(automatycznie generowane przez ASP.NET ramy:)

(1) Adres URL nie znajduje dopasowania w tabeli tras.

(automatycznie generowane przez ASP.NET MVC Framework:)

(2) adres URL znajduje dopasowanie w tabeli tras, ale określa nieistniejący kontroler.

(3) adres URL znajduje dopasowanie w tabeli tras, ale określa nieistniejącą akcję.

(generowane ręcznie:)

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

(5) akcja powoduje wywołanie HttpException o kodzie stanu 404.

(6) akcja ręcznie modyfikuje odpowiedź.Właściwość StatusCode do 404.

Zwykle chcesz osiągnąć 3 cele:

(1) wyświetla Użytkownikowi niestandardową stronę błędu 404.

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

(3) wyślij odpowiedź bezpośrednio, bez przekierowania 302.

Istnieją różne sposoby, aby to osiągnąć:

(1)

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

Problemy z tym rozwiązaniem:

  1. nie spełnia celu (1) w przypadkach (1), (4), (6).
  2. nie spełnia automatycznie celu (2). Musi być zaprogramowany ręcznie.
  3. nie spełnia celu (3).

(2)

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

Problemy z tym rozwiązanie:

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

(3)

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

  1. działa tylko na IIS 7+.
  2. nie spełnia automatycznie celu (2). Musi być zaprogramowany ręcznie.
  3. zasłania http na poziomie aplikacji wyjątki. 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.

(4)

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

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

Ludzie, którzy mają kłopoty z tym przed nawet próbował utworzyć własne biblioteki (patrz http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html ). jednak poprzednie rozwiązanie wydaje się obejmować wszystkie przypadki bez złożoności korzystania z zewnętrznej biblioteki.

 82
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
2012-05-22 22:29:22

Naprawdę podoba mi się rozwiązanie cottsaks i myślę, że jest bardzo jasno wyjaśnione. moim jedynym dodatkiem było zmienić Krok 2 w następujący sposób

public abstract class MyController : Controller
{

    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        //if controller is ErrorController dont 'nest' exceptions
        if(this.GetType() != typeof(ErrorController))
        this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}

Zasadniczo powstrzymuje to adresy URL zawierające nieprawidłowe akcje i kontrolery przed dwukrotnym uruchomieniem procedury wyjątku. np. dla adresów URL takich jak asdfsdf / dfgdfgd

 13
Author: Dave Lowe,
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
2010-11-01 06:16:22

Jedynym sposobem, aby metoda @ cottsak działała dla nieprawidłowych kontrolerów, było zmodyfikowanie istniejącego żądania trasy w CustomControllerFactory, tak:

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(requestContext, controllerType); 
            else
                return ObjectFactory.GetInstance(controllerType) as Controller;
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
            {
                requestContext.RouteData.Values["controller"] = "Error";
                requestContext.RouteData.Values["action"] = "Http404";
                requestContext.RouteData.Values.Add("url", requestContext.HttpContext.Request.Url.OriginalString);

                return ObjectFactory.GetInstance<ErrorController>();
            }
            else
                throw ex;
        }
    }
}

Powinienem wspomnieć, że używam MVC 2.0.

 6
Author: Dave K,
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
2010-07-29 23:43:14

Oto kolejna metoda wykorzystująca narzędzia MVC, która może obsługiwać żądania złych nazw kontrolerów, złych nazw tras i innych kryteriów, które według ciebie pasują do metody akcji. Osobiście wolę unikać jak największej liczby stron internetowych.ustawienia config, jak to możliwe, ponieważ robią przekierowanie 302 / 200 i nie obsługują ResponseRewrite (Server.Transfer) używając widoku Razor. Wolałbym zwrócić 404 z niestandardową stroną błędu ze względów SEO.

Niektóre z nich to nowe spojrzenie na technikę cottsaka powyżej.

To rozwiązanie wykorzystuje również minimal web.ustawienia konfiguracyjne faworyzujące filtry błędów MVC 3.

Użycie

Po prostu wyrzuć HttpException z akcji lub niestandardowego filtra ActionFilterAttribute.

Throw New HttpException(HttpStatusCode.NotFound, "[Custom Exception Message Here]")

Krok 1

Dodaj następujące ustawienie do swojej sieci.config. Jest to wymagane do użycia HandleErrorAttribute MVC.

<customErrors mode="On" redirectMode="ResponseRedirect" />

Krok 2

Dodaj niestandardowy HandleHttpErrorAttribute podobny do HandleErrorAttribute frameworka MVC, z wyjątkiem dla błędów HTTP:

<AttributeUsage(AttributeTargets.All, AllowMultiple:=True)>
Public Class HandleHttpErrorAttribute
    Inherits FilterAttribute
    Implements IExceptionFilter

    Private Const m_DefaultViewFormat As String = "ErrorHttp{0}"

    Private m_HttpCode As HttpStatusCode
    Private m_Master As String
    Private m_View As String

    Public Property HttpCode As HttpStatusCode
        Get
            If m_HttpCode = 0 Then
                Return HttpStatusCode.NotFound
            End If
            Return m_HttpCode
        End Get
        Set(value As HttpStatusCode)
            m_HttpCode = value
        End Set
    End Property

    Public Property Master As String
        Get
            Return If(m_Master, String.Empty)
        End Get
        Set(value As String)
            m_Master = value
        End Set
    End Property

    Public Property View As String
        Get
            If String.IsNullOrEmpty(m_View) Then
                Return String.Format(m_DefaultViewFormat, Me.HttpCode)
            End If
            Return m_View
        End Get
        Set(value As String)
            m_View = value
        End Set
    End Property

    Public Sub OnException(filterContext As System.Web.Mvc.ExceptionContext) Implements System.Web.Mvc.IExceptionFilter.OnException
        If filterContext Is Nothing Then Throw New ArgumentException("filterContext")

        If filterContext.IsChildAction Then
            Return
        End If

        If filterContext.ExceptionHandled OrElse Not filterContext.HttpContext.IsCustomErrorEnabled Then
            Return
        End If

        Dim ex As HttpException = TryCast(filterContext.Exception, HttpException)
        If ex Is Nothing OrElse ex.GetHttpCode = HttpStatusCode.InternalServerError Then
            Return
        End If

        If ex.GetHttpCode <> Me.HttpCode Then
            Return
        End If

        Dim controllerName As String = filterContext.RouteData.Values("controller")
        Dim actionName As String = filterContext.RouteData.Values("action")
        Dim model As New HandleErrorInfo(filterContext.Exception, controllerName, actionName)

        filterContext.Result = New ViewResult With {
            .ViewName = Me.View,
            .MasterName = Me.Master,
            .ViewData = New ViewDataDictionary(Of HandleErrorInfo)(model),
            .TempData = filterContext.Controller.TempData
        }
        filterContext.ExceptionHandled = True
        filterContext.HttpContext.Response.Clear()
        filterContext.HttpContext.Response.StatusCode = Me.HttpCode
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = True
    End Sub
End Class

Krok 3

Dodaj filtry do GlobalFilterCollection (GlobalFilters.Filters) w Global.asax. Ten przykład przekieruje wszystkie błędy InternalServerError (500) do widoku współdzielonego błędu (Views/Shared/Error.vbhtml). Błędy NotFound (404) zostaną wysłane do ErrorHttp404.vbhtml również we współdzielonych widokach. Dodałem tutaj Błąd 401, aby pokazać, jak można to rozszerzyć o dodatkowe kody błędów HTTP. Zauważ, że muszą to być wspólne widoki i wszystkie używają obiektu System.Web.Mvc.HandleErrorInfo jako model.

filters.Add(New HandleHttpErrorAttribute With {.View = "ErrorHttp401", .HttpCode = HttpStatusCode.Unauthorized})
filters.Add(New HandleHttpErrorAttribute With {.View = "ErrorHttp404", .HttpCode = HttpStatusCode.NotFound})
filters.Add(New HandleErrorAttribute With {.View = "Error"})

Krok 4

Utwórz podstawową klasę kontrolera i Dziedzicz z niej w kontrolerach. Ten krok pozwala nam obsłużyć nieznane nazwy akcji i podnieść Błąd HTTP 404 do naszego HandleHttpErrorAttribute.

Public Class BaseController
    Inherits System.Web.Mvc.Controller

    Protected Overrides Sub HandleUnknownAction(actionName As String)
        Me.ActionInvoker.InvokeAction(Me.ControllerContext, "Unknown")
    End Sub

    Public Function Unknown() As ActionResult
        Throw New HttpException(HttpStatusCode.NotFound, "The specified controller or action does not exist.")
        Return New EmptyResult
    End Function
End Class

Krok 5

Utwórz nadpisanie ControllerFactory i nadpisanie go w Twoim globalnym.plik asax w Application_Start. Ten krok pozwala nam podnieść wyjątek HTTP 404, gdy Niepoprawna nazwa kontrolera została określone.

Public Class MyControllerFactory
    Inherits DefaultControllerFactory

    Protected Overrides Function GetControllerInstance(requestContext As System.Web.Routing.RequestContext, controllerType As System.Type) As System.Web.Mvc.IController
        Try
            Return MyBase.GetControllerInstance(requestContext, controllerType)
        Catch ex As HttpException
            Return DependencyResolver.Current.GetService(Of BaseController)()
        End Try
    End Function
End Class

'In Global.asax.vb Application_Start:

controllerBuilder.Current.SetControllerFactory(New MyControllerFactory)

Krok 6

Dołącz specjalną trasę do tabeli tras.Trasy dla akcji BaseController Unknown. To pomoże nam podnieść 404 w przypadku, gdy użytkownik uzyskuje dostęp do nieznanego kontrolera lub nieznanej akcji.

'BaseController
routes.MapRoute( _
    "Unknown", "BaseController/{action}/{id}", _
    New With {.controller = "BaseController", .action = "Unknown", .id = UrlParameter.Optional} _
)

Podsumowanie

Ten przykład zademonstrował, w jaki sposób można użyć frameworka MVC, aby zwrócić 404 kody błędów Http do przeglądarki bez przekierowania, używając atrybutów filtrów i wspólnych widoków błędów. Pokazuje również pokazanie tego samego niestandardowa strona błędu, gdy podano niepoprawne nazwy kontrolerów i nazwy akcji.

Dodam zrzut ekranu nieprawidłowej nazwy kontrolera, nazwy akcji i niestandardowego 404 podniesionego z akcji Home / TriggerNotFound, jeśli dostanę wystarczającą ilość głosów, aby dodać jeden =). Fiddler zwraca wiadomość 404, gdy uzyskuję dostęp do następujących adresów URL za pomocą tego rozwiązania:

/InvalidController
/Home/InvalidRoute
/InvalidController/InvalidRoute
/Home/TriggerNotFound

Post Cottsaka powyżej i te artykuły były dobrymi referencjami.

 4
Author: sky-dev,
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-04-12 07:31:25

Moje skrócone rozwiązanie, które działa z nieobsługiwanymi obszarami, kontrolerami i akcjami:

  1. Utwórz widok 404.cshtml.

  2. Utwórz klasę bazową dla kontrolerów:

    public class Controller : System.Web.Mvc.Controller
    {
        protected override void HandleUnknownAction(string actionName)
        {
            Http404().ExecuteResult(ControllerContext);
        }
    
        protected virtual ViewResult Http404()
        {
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            return View("404");
        }
    }
    
  3. Utwórz niestandardową fabrykę kontrolerów zwracając kontroler bazowy jako rezerwowy:

    public class ControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (controllerType != null)
                return base.GetControllerInstance(requestContext, controllerType);
    
            return new Controller();
        }
    }
    
  4. Dodaj do Application_Start() następujący wiersz:

    ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));
    
 4
Author: Herman Kan,
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
2014-05-23 13:09:51

W MVC4 WebAPI 404 mogą być obsługiwane w następujący sposób,

KURSY APICONTROLLER

    // GET /api/courses/5
    public HttpResponseMessage<Courses> Get(int id)
    {
        HttpResponseMessage<Courses> resp = null;

        var aCourse = _courses.Where(c => c.Id == id).FirstOrDefault();

        resp = aCourse == null ? new HttpResponseMessage<Courses>(System.Net.HttpStatusCode.NotFound) : new HttpResponseMessage<Courses>(aCourse);

        return resp;
    }

HOME CONTROLLER

public ActionResult Course(int id)
{
    return View(id);
}

Widok

<div id="course"></div>
<script type="text/javascript">
    var id = @Model;
    var course = $('#course');
    $.ajax({    
        url: '/api/courses/' + id,
        success: function (data) {
            course.text(data.Name);
        },
        statusCode: {
            404: function() 
            {
                course.text('Course not available!');    
            }
        }
    });
</script>

GLOBAL

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

Wyniki

Tutaj wpisz opis obrazka

 3
Author: Diganta Kumar,
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-05-08 12:59:48

Spróbuj NotFoundMVC na nuget. To działa, bez konfiguracji.

 2
Author: DarthVader,
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
2013-07-09 14:06:53

Moje rozwiązanie, na wypadek, gdyby ktoś uznał je za przydatne.

W Sieci.config:

<system.web>
    <customErrors mode="On" defaultRedirect="Error" >
      <error statusCode="404" redirect="~/Error/PageNotFound"/>
    </customErrors>
    ...
</system.web>

W Controllers/ErrorController.cs:

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        if(Request.IsAjaxRequest()) {
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            return Content("Not Found", "text/plain");
        }

        return View();
    }
}

Dodaj PageNotFound.cshtml do folderu Shared i to wszystko.

 2
Author: Konamiman,
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
2013-10-01 10:31:13

Wydaje mi się, że standardowa konfiguracja CustomErrors powinna po prostu działać jednak ze względu na zależność od Server.Transfer wydaje się, że wewnętrzna implementacja ResponseRewrite nie jest zgodna z MVC.

Wydaje mi się to rażącą dziurą w funkcjonalności, więc postanowiłem ponownie zaimplementować tę funkcję za pomocą modułu HTTP. Poniższe rozwiązanie pozwala obsłużyć dowolny kod statusu HTTP (w tym 404) poprzez przekierowanie na dowolną ważną trasę MVC, tak jak byś to zrobił normalnie.

<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="404.aspx" />
    <error statusCode="500" redirect="~/MVCErrorPage" />
</customErrors>

To zostało przetestowane na następujących platformach;

    [17]}MVC4 w trybie zintegrowanego rurociągu (IIS Express 8) [[17]} MVC4 w trybie klasycznym (VS Development Server, Cassini)
  • MVC4 w trybie klasycznym (IIS6)

Korzyści

  • ogólne rozwiązanie, które można wrzucić do dowolnego projektu MVC
  • umożliwia obsługę tradycyjnej konfiguracji błędów niestandardowych
  • Działa zarówno w zintegrowanym rurociągu, jak i Tryby klasyczne

Rozwiązanie

namespace Foo.Bar.Modules {

    /// <summary>
    /// Enables support for CustomErrors ResponseRewrite mode in MVC.
    /// </summary>
    public class ErrorHandler : IHttpModule {

        private HttpContext HttpContext { get { return HttpContext.Current; } }
        private CustomErrorsSection CustomErrors { get; set; }

        public void Init(HttpApplication application) {
            System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
            CustomErrors = (CustomErrorsSection)configuration.GetSection("system.web/customErrors");

            application.EndRequest += Application_EndRequest;
        }

        protected void Application_EndRequest(object sender, EventArgs e) {

            // only handle rewrite mode, ignore redirect configuration (if it ain't broke don't re-implement it)
            if (CustomErrors.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite && HttpContext.IsCustomErrorEnabled) {

                int statusCode = HttpContext.Response.StatusCode;

                // if this request has thrown an exception then find the real status code
                Exception exception = HttpContext.Error;
                if (exception != null) {
                    // set default error status code for application exceptions
                    statusCode = (int)HttpStatusCode.InternalServerError;
                }

                HttpException httpException = exception as HttpException;
                if (httpException != null) {
                    statusCode = httpException.GetHttpCode();
                }

                if ((HttpStatusCode)statusCode != HttpStatusCode.OK) {

                    Dictionary<int, string> errorPaths = new Dictionary<int, string>();

                    foreach (CustomError error in CustomErrors.Errors) {
                        errorPaths.Add(error.StatusCode, error.Redirect);
                    }

                    // find a custom error path for this status code
                    if (errorPaths.Keys.Contains(statusCode)) {
                        string url = errorPaths[statusCode];

                        // avoid circular redirects
                        if (!HttpContext.Request.Url.AbsolutePath.Equals(VirtualPathUtility.ToAbsolute(url))) {

                            HttpContext.Response.Clear();
                            HttpContext.Response.TrySkipIisCustomErrors = true;

                            HttpContext.Server.ClearError();

                            // do the redirect here
                            if (HttpRuntime.UsingIntegratedPipeline) {
                                HttpContext.Server.TransferRequest(url, true);
                            }
                            else {
                                HttpContext.RewritePath(url, false);

                                IHttpHandler httpHandler = new MvcHttpHandler();
                                httpHandler.ProcessRequest(HttpContext);
                            }

                            // return the original status code to the client
                            // (this won't work in integrated pipleline mode)
                            HttpContext.Response.StatusCode = statusCode;

                        }
                    }

                }

            }

        }

        public void Dispose() {

        }


    }

}

Użycie

Dołącz to jako ostateczny moduł HTTP w swojej sieci.config

  <system.web>
    <httpModules>
      <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
    </httpModules>
  </system.web>

  <!-- IIS7+ -->
  <system.webServer>
    <modules>
      <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
    </modules>
  </system.webServer>

Dla tych z Was, którzy zwracają uwagę, zauważycie, że w trybie zintegrowanego potoku zawsze będzie to odpowiadać HTTP 200 ze względu na sposób działania Server.TransferRequest. Aby zwrócić właściwy kod błędu używam poniższego kontrolera błędów.

public class ErrorController : Controller {

    public ErrorController() { }

    public ActionResult Index(int id) {
        // pass real error code to client
        HttpContext.Response.StatusCode = id;
        HttpContext.Response.TrySkipIisCustomErrors = true;

        return View("Errors/" + id.ToString());
    }

}
 2
Author: Red Taz,
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
2015-03-31 15:39:03

Radzenie sobie z błędami w ASP.NET MVC to tylko wrzód na tyłku. Próbowałem wiele sugestii na tej stronie i na inne pytania i strony i nic nie działa dobrze. Jedną z sugestii było usunięcie błędów w sieci.config wewnątrz systemu.webserver ale to po prostu zwraca puste strony.

Moim celem przy wymyślaniu tego rozwiązania było;

  • NIE REDIRECT
  • zwraca poprawne KODY STANU Nie 200 / Ok jak domyślne obsługa błędów
Oto moje rozwiązanie.

1.Dodaj następujący tekst do systemu.web section

   <system.web>
     <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404"  redirect="~/Error/404.aspx" />
      <error statusCode="500" redirect="~/Error/500.aspx" />
     </customErrors>
    <system.web>

Powyższe obsługuje wszystkie adresy URL, które nie są obsługiwane przez trasy .config i nieobsługiwane wyjątki, szczególnie te spotykane w widokach. Zauważ, że użyłem aspx nie html . To dlatego mogę dodać kod odpowiedzi na kod z tyłu.

2. Utwórz folder o nazwie Error (czy jak wolisz) w korzeń twojego projektu i dodaj dwa formularze internetowe. Poniżej moja 404 Strona;

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="404.aspx.cs" Inherits="Myapp.Error._404" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title >Page Not found</title>
    <link href="<%=ResolveUrl("~/Content/myapp.css")%>" rel="stylesheet" />
</head>
<body>
    <div class="top-nav">
      <a runat="server" class="company-logo" href="~/"></a>
    </div>
    <div>
        <h1>404 - Page Not found</h1>
        <p>The page you are looking for cannot be found.</p>
        <hr />
        <footer></footer>
    </div>
</body>
</html>

A na kodzie za ustawiłem kod odpowiedzi

protected void Page_Load(object sender, EventArgs e)
{
    Response.StatusCode = 404;
}

Zrób to samo dla 500 stron

3.do obsługi błędów w kontrolerach. Można to zrobić na wiele sposobów. To mi się udało. Wszystkie moje Kontrolery dziedziczą po kontrolerze bazowym. W kontrolerze bazowym mam następujące metody

protected ActionResult ShowNotFound()
{
    return ShowNotFound("Page not found....");
}

protected ActionResult ShowNotFound(string message)
{
    return ShowCustomError(HttpStatusCode.NotFound, message);
}

protected ActionResult ShowServerError()
{
    return ShowServerError("Application error....");
}

protected ActionResult ShowServerError(string message)
{
    return ShowCustomError(HttpStatusCode.InternalServerError, message);
}

protected ActionResult ShowNotAuthorized()
{
    return ShowNotAuthorized("You are not allowed ....");

}

protected ActionResult ShowNotAuthorized(string message)
{
    return ShowCustomError(HttpStatusCode.Forbidden, message);
}

protected ActionResult ShowCustomError(HttpStatusCode statusCode, string message)
{
    Response.StatusCode = (int)statusCode;
    string title = "";
    switch (statusCode)
    {
        case HttpStatusCode.NotFound:
            title = "404 - Not found";
            break;
        case HttpStatusCode.Forbidden:
            title = "403 - Access Denied";
            break;
        default:
            title = "500 - Application Error";
            break;
    }
    ViewBag.Title = title;
    ViewBag.Message = message;
    return View("CustomError");
}

4.Dodaj CustomError.cshtml to your Shared folder widoki. Poniżej jest mój;

<h1>@ViewBag.Title</h1>
<br />
<p>@ViewBag.Message</p>

Teraz w kontrolerze aplikacji możesz zrobić coś takiego;

public class WidgetsController : ControllerBase
{
  [HttpGet]
  public ActionResult Edit(int id)
  {
    Try
    {
       var widget = db.getWidgetById(id);
       if(widget == null)
          return ShowNotFound();
          //or return ShowNotFound("Invalid widget!");
       return View(widget);
    }
    catch(Exception ex)
    {
       //log error
       logger.Error(ex)
       return ShowServerError();
    }
  }
}

A teraz zastrzeżenie. Nie obsługuje statycznych błędów plików. Więc jeśli masz trasę taką jak example.com/widgets a użytkownik zmienia go na example.com/widgets.html , otrzymają domyślną stronę błędu IIS, więc musisz obsłużyć błędy poziomu IIS w inny sposób.

 2
Author: Moses Machua,
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
2016-09-01 12:08:24

Zamieszczanie odpowiedzi, ponieważ mój komentarz był zbyt długi...

To zarówno komentarz jak i pytania do wpisu/odpowiedzi:

Https://stackoverflow.com/a/7499406/687549

Wolę tę odpowiedź od innych ze względu na prostotę i fakt, że najwyraźniej konsultowano się z niektórymi osobami z Microsoftu. Mam jednak trzy pytania i jeśli można na nie odpowiedzieć, nazwę tę odpowiedź Świętym Graalem wszystkich odpowiedzi błędów 404/500 na interwebs dla ASP.NET Aplikacja MVC (x).

@Pure.Krome

  1. Czy możesz zaktualizować swoją odpowiedź o SEO z komentarzy wskazywanych przez GWB (nigdy nie było o tym wzmianki w twojej odpowiedzi) - <customErrors mode="On" redirectMode="ResponseRewrite"> i <httpErrors errorMode="Custom" existingResponse="Replace">?

  2. Możesz zapytać swojego ASP.NET przyjaciele zespołu jeśli można to zrobić w ten sposób-byłoby miło mieć jakieś potwierdzenie-może to duże Nie-Nie zmienić redirectMode i existingResponse w ten sposób, aby móc ładnie grać z SEO?!

  3. Możesz dodać trochę wyjaśnienie tego wszystkiego (customErrors redirectMode="ResponseRewrite", customErrors redirectMode="ResponseRedirect", httpErrors errorMode="Custom" existingResponse="Replace", usunąć customErrors CAŁKOWICIE jak ktoś zasugerował) po rozmowie ze znajomymi z Microsoftu?

Jak już mówiłem, byłoby supernice, gdybyśmy mogli uzupełnić Twoją odpowiedź, ponieważ wydaje się to dość popularne pytanie z ponad 54 000 odsłon.

Update: odpowiedź jednorożca robi 302 Znalezione i 200 OK i nie można go zmienić, aby zwrócić tylko 404 za pomocą trasy. Musi to być plik fizyczny, który nie jest bardzo MVC:) Przechodzimy więc do innego rozwiązania. Szkoda, bo to wydawało się być ostatecznym MVC: ish odpowiedź tak daleko.

 1
Author: PussInBoots,
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 11:47:28

Dodanie mojego rozwiązania, które jest prawie identyczne z rozwiązaniem Hermana Kana, z małą zmarszczką, aby umożliwić to działanie dla mojego projektu.

Tworzenie niestandardowego kontrolera błędów:

public class Error404Controller : BaseController
{
    [HttpGet]
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View("404");
    }
}

Następnie utwórz niestandardową fabrykę kontrolerów:

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        return controllerType == null ? new Error404Controller() : base.GetControllerInstance(requestContext, controllerType);
    }
}

Na koniec dodaj nadpisanie do niestandardowego kontrolera błędów:

protected override void HandleUnknownAction(string actionName)
{
    var errorRoute = new RouteData();
    errorRoute.Values.Add("controller", "Error404");
    errorRoute.Values.Add("action", "PageNotFound");
    new Error404Controller().Execute(new RequestContext(HttpContext, errorRoute));
}
I to wszystko. Nie ma potrzeby tworzenia sieci.zmiany konfiguracji.
 1
Author: Rob Lyndon,
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-02-03 12:44:39

1) Stwórz abstrakcyjną klasę kontrolera.

public abstract class MyController:Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;
        return View("NotFound");
    }

    protected override void HandleUnknownAction(string actionName)
    {
        this.ActionInvoker.InvokeAction(this.ControllerContext, "NotFound");
    }
    protected override void OnAuthorization(AuthorizationContext filterContext) { }
}  

2) Stwórz dziedziczenie z tej abstrakcyjnej klasy w swoich kontrolerach

public class HomeController : MyController
{}  

3) i dodaj widok o nazwie "NotFound" w folderze View-Shared.

 1
Author: Mehmet,
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-02-20 13:21:06

Przejrzałem większość rozwiązań zamieszczonych w tym wątku. Chociaż to pytanie może być Stare, to nadal ma zastosowanie do nowych projektów nawet teraz, więc spędziłem sporo czasu czytając odpowiedzi przedstawione tutaj, jak również gdzie indziej.

Jak @Marco zwrócił uwagę na różne przypadki, w których może się zdarzyć 404, sprawdziłem rozwiązanie, które zestawiłem razem z tą listą. Oprócz jego listy wymagań, dodałem jeszcze jeden.

  • roztwór powinien być w stanie obsłużyć MVC, jak również AJAX/WebAPI wywołań w najbardziej odpowiedni sposób. (tzn. jeśli 404 dzieje się w MVC, powinien pokazać stronę Not Found, a jeśli 404 dzieje się w WebAPI, nie powinien przejmować odpowiedzi XML / JSON, aby konsumujący Javascript mógł ją łatwo przeanalizować).

Rozwiązanie to jest 2-krotne:

Pierwsza część pochodzi od @Guillaume at https://stackoverflow.com/a/27354140/2310818 . ich rozwiązanie zajmuje się każdym 404, które były spowodowane nieprawidłową trasą, nieprawidłowym kontrolerem i nieprawidłową akcją.

Chodzi o stworzenie formularza internetowego, a następnie wywołanie akcji NotFound kontrolera błędów MVC. Robi to wszystko bez żadnych przekierowań, więc nie zobaczysz ani jednego 302 w Fiddler. Oryginalny adres URL jest również zachowany, co sprawia, że to rozwiązanie jest fantastyczne!


Druga część pochodzi z @ Germán at https://stackoverflow.com/a/5536676/2310818 . ich rozwiązanie zajmuje się każdym 404 zwracane przez twoje działania w postaci HttpNotFoundResult () lub throw new HttpException()!

Chodzi o to, aby filtr spojrzał na odpowiedź, a także wyjątek rzucany przez kontrolery MVC i wywołał odpowiednią akcję w kontrolerze błędów. Ponownie to rozwiązanie działa bez żadnych przekierowań i oryginalny adres URL jest zachowany!


Jak widać, oba te rozwiązania razem oferują bardzo solidny mechanizm obsługi błędów i osiągają wszystkie wymagania wymienione przez @ Marco, jak również moje wymagania. Jeśli chcesz zobaczyć działającą próbkę lub demo tego rozwiązania, zostaw w komentarzach, a ja chętnie je złożę.

 0
Author: Parth Shah,
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 11:54:58

Przejrzałem Wszystkie artykuły, ale nic nie działa dla mnie: Moje Wymaganie Wpisz cokolwiek w swoim adresie URL niestandardowa strona 404 powinna pokazać.Myślałem, że to bardzo proste.Ale powinieneś dobrze zrozumieć obsługę 404:

 <system.web>
    <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404" redirect="~/PageNotFound.aspx"/>
    </customErrors>
  </system.web>
<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404"/>
      <error statusCode="404" path="/PageNotFound.html" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

Uważam ten artykuł za bardzo pomocny.powinien być przeczytany od razu.Custome error page-Ben Foster

 0
Author: Thakur Rock,
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
2015-07-30 06:23:55