webentwicklung-frage-antwort-db.com.de

ASP.NET MVC 404-Fehlerbehandlung

Mögliches Duplikat:
Wie kann ich mit 404 in ASP.NET MVC richtig umgehen?

Ich habe die unter 404-HTTP-Fehlerbehandlungsroutine in Asp.Net MVC (RC 5) beschriebenen Änderungen vorgenommen und erhalte weiterhin die Standard-404-Fehlerseite. Muss ich etwas in IIS ändern?

129
Clearly

Noch eine andere Lösung.

Fügen Sie ErrorControllers oder eine statische Seite mit 404-Fehlerinformationen hinzu.

Ändern Sie Ihre web.config (im Falle eines Controllers).

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

Oder im Falle einer statischen Seite

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

Dies behandelt sowohl verpasste Routen als auch verpasste Aktionen.

142
Mike Chaliy

Ich habe VIEL untersucht, wie man 404s in MVC richtig verwaltet (speziell MVC3) und dies, IMHO ist die beste Lösung, die ich mir ausgedacht habe:

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

Bearbeiten:

Wenn Sie IoC (z. B. AutoFac) verwenden, sollten Sie Ihren Controller wie folgt erstellen:

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

Anstatt

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

(Optional)

Erklärung:

Es gibt 6 Szenarien, in denen ASP.NET MVC3-Apps 404-Werte erzeugen können.

Generiert von ASP.NET:

  • Szenario 1: Die URL stimmt nicht mit einer Route in der Routentabelle überein.

Generiert von ASP.NET MVC:

  • Szenario 2: Die URL stimmt mit einer Route überein, gibt jedoch einen Controller an, der nicht vorhanden ist.

  • Szenario 3: Die URL stimmt mit einer Route überein, gibt jedoch eine Aktion an, die nicht vorhanden ist.

Manuell generiert:

  • Szenario 4: Eine Aktion gibt ein HttpNotFoundResult mit der Methode HttpNotFound () zurück.

  • Szenario 5: Eine Aktion löst eine HttpException mit dem Statuscode 404 aus.

  • Szenario 6: Durch eine Aktion wird die Response.StatusCode-Eigenschaft manuell in 404 geändert.

Ziele

  • (A) Zeigt dem Benutzer eine benutzerdefinierte 404-Fehlerseite an.

  • (B) Pflegen Sie den 404-Statuscode in der Kundenantwort (besonders wichtig für SEO).

  • (C) Senden Sie die Antwort direkt, ohne eine 302-Umleitung zu erfordern.

Lösungsversuch: Benutzerdefinierte Fehler

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

Probleme mit dieser Lösung:

  • Entspricht nicht Ziel (A) in den Szenarien (1), (4), (6).
  • Entspricht nicht automatisch dem Ziel (B). Es muss manuell programmiert werden.
  • Entspricht nicht dem Ziel (C).

Lösungsversuch: HTTP-Fehler

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

Probleme mit dieser Lösung:

  • Funktioniert nur mit IIS 7+.
  • Entspricht nicht Ziel (A) in den Szenarien (2), (3), (5).
  • Entspricht nicht automatisch dem Ziel (B). Es muss manuell programmiert werden.

Lösungsversuch: HTTP-Fehler mit Ersetzen

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

Probleme mit dieser Lösung:

  • Funktioniert nur mit IIS 7+.
  • Entspricht nicht automatisch dem Ziel (B). Es muss manuell programmiert werden.
  • Es verdeckt http-Ausnahmen auf Anwendungsebene. Z.B. Ich kann den Abschnitt customErrors, System.Web.Mvc.HandleErrorAttribute usw. nicht verwenden. Es können nicht nur allgemeine Fehlerseiten angezeigt werden.

Lösungsversuch: customErrors und HTTP-Fehler

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

und

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

Probleme mit dieser Lösung:

  • Funktioniert nur mit IIS 7+.
  • Entspricht nicht automatisch dem Ziel (B). Es muss manuell programmiert werden.
  • Entspricht nicht Ziel (C) in den Szenarien (2), (3), (5).

Leute, die sich zuvor damit befasst haben, haben sogar versucht, ihre eigenen Bibliotheken zu erstellen (siehe http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html ). Die vorherige Lösung scheint jedoch alle Szenarien abzudecken, ohne die Komplexität der Verwendung einer externen Bibliothek.

360
Marco

Die Antwort von Marco ist die BESTE Lösung. Ich musste meine Fehlerbehandlung kontrollieren, und ich meine es wirklich KONTROLLIEREN. Natürlich habe ich die Lösung ein wenig erweitert und ein vollständiges Fehlermanagementsystem geschaffen, das alles verwaltet. Ich habe auch in anderen Blogs über diese Lösung gelesen und sie scheint für die meisten fortgeschrittenen Entwickler sehr akzeptabel zu sein.

Hier ist der endgültige Code, den ich verwende:

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

und in meinem ErrorManagerController:

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

Jetzt löse ich in meiner Aktion eine benutzerdefinierte Ausnahme aus, die ich erstellt habe. Mein Controller erbt von einer benutzerdefinierten Controller-basierten Klasse, die ich erstellt habe. Der Custom Base Controller wurde erstellt, um die Fehlerbehandlung zu überschreiben. Hier ist meine benutzerdefinierte Base Controller-Klasse:

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

Der "ErrorManager" im obigen Code ist nur eine Ansicht, die ein auf ExceptionContext basierendes Modell verwendet

Meine Lösung funktioniert einwandfrei und ich kann mit JEDEM Fehler auf meiner Website umgehen und je nach Ausnahmetyp unterschiedliche Meldungen anzeigen.

5
Yousi

Sieht aus wie dies der beste Weg ist, um alles zu fangen.

Wie kann ich mit 404 in ASP.NET MVC richtig umgehen?

4
Clearly

In IIS können Sie basierend auf dem Fehlercode eine Weiterleitung zu einer "bestimmten" Seite angeben. In Ihrem Beispiel können Sie 404 -> Ihre angepasste 404-Fehlerseite konfigurieren.

1
J.W.

Was ich empfehlen kann, ist auf FilterAttribute zu suchen. MVC verfügt beispielsweise bereits über HandleErrorAttribute. Sie können es anpassen, um nur 404 zu behandeln. Antworten Sie, wenn Sie interessiert sind, ich werde Beispiel aussehen.

BTW

Lösung (mit letzter Route), die Sie in der vorherigen Frage akzeptiert haben, funktioniert in vielen Situationen nicht. Die zweite Lösung mit HandleUnknownAction funktioniert, erfordert jedoch, dass diese Änderung in jedem Controller vorgenommen wird oder ein einzelner Basiscontroller vorhanden ist.

Meine Wahl ist eine Lösung mit HandleUnknownAction.

1
Mike Chaliy