446 Stimmen

Wie kann ich 404 in ASP.NET MVC ordnungsgemäß behandeln?

Ich benutze RC2

Die Verwendung von URL-Routing:

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

Das obige scheint Anfragen wie diese zu bearbeiten (unter der Annahme der Standard-Routen, die beim initialen MVC-Projekt eingerichtet wurden): "/blah/blah/blah/blah"

Überschreiben von HandleUnknownAction() im Controller selbst:

// 404s - hier behandeln (falsche Aktion angefordert
protected override void HandleUnknownAction(string actionName) {
    ViewData["actionName"] = actionName;
    View("NotFound").ExecuteResult(this.ControllerContext);
}  

Die bisherigen Strategien behandeln jedoch keine Anfrage an einen schlechten/ unbekannten Controller. Wenn ich zum Beispiel keinen "/IDoNotExist" habe, und diesen anfordere, erhalte ich die generische 404-Seite vom Webserver und nicht meine 404, wenn ich Routing + Überschreibung verwende.

Meine Frage lautet also: Gibt es eine Möglichkeit, diese Art von Anfrage innerhalb des MVC-Frameworks selbst mit einer Route oder ähnlichem abzufangen?

ODER sollte ich einfach standardmäßig die Web.Config customErrors als meinen 404-Handler verwenden und all dies vergessen? Ich nehme an, wenn ich customErrors verwende, werde ich die generische 404-Seite außerhalb von /Views speichern müssen, aufgrund der Einschränkungen von Web.Config bezüglich des direkten Zugriffs.

3 Stimmen

Es handelt sich um einen 404-Fehler, ich würde mich einfach nicht darum kümmern. Lassen Sie ihn 404 anzeigen, da der Benutzer definitiv etwas falsch eingegeben hat. Oder wenn es sich um etwas handelt, das verschoben wurde, sollte Ihre Anwendung diese Anfrage entgegennehmen und eine permanente Weiterleitung durchführen. 404 gehört zum Webserver, nicht zur Anwendung. Sie können immer IIS-Seiten für Fehler anpassen.

0 Stimmen

Sie können sich auch diese Lösung ansehen blog.dantup.com/2009/04/…

0 Stimmen

ben.onfabrik.com/posts/aspnet-mvc-custom-error-pages hat auch einige gute Informationen.

3voto

Moses Machua Punkte 10482

Der Umgang mit Fehlern in ASP.NET MVC ist einfach lästig. Ich habe eine Menge Vorschläge auf dieser Seite und auf anderen Fragen und Websites ausprobiert und nichts funktioniert gut. Ein Vorschlag war, Fehler in web.config innerhalb von system.webserver zu behandeln, aber das führt nur zu leeren Seiten.

Mein Ziel bei der Entwicklung dieser Lösung war es, folgendes zu erreichen:

  • NICHT WEITERLEITEN
  • KORREKTE STATUSCODES zurückgeben, nicht 200/OK wie die Standardfehlerbehandlung

Hier ist meine Lösung.

1. Fügen Sie folgendes im Abschnitt system.web hinzu

Das oben genannte behandelt alle URLs, die nicht von routes.config behandelt werden, und nicht behandelte Ausnahmen, insbesondere solche, die in den Ansichten auftreten. Beachten Sie, dass ich aspx und nicht html verwendet habe. Dies ermöglicht es mir, einen Antwortcode im Codebehind hinzuzufügen.

2. Erstellen Sie einen Ordner namens Error (oder wie auch immer Sie es bevorzugen) im Root Ihres Projekts und fügen Sie die beiden Webformulare hinzu. Hier ist meine 404-Seite;

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

    Seite nicht gefunden
    " rel="stylesheet" />

        404 - Seite nicht gefunden
        Die gesuchte Seite konnte nicht gefunden werden.

Und im Codebehind setze ich den Antwortcode

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

Machen Sie dasselbe für die 500-Seite

3. Um Fehler innerhalb der Controller zu behandeln, gibt es viele Möglichkeiten. Das ist, was für mich funktioniert hat. Alle meine Controller erben von einem Basiskontroller. In diesem Basiskontroller habe ich die folgenden Methoden

protected ActionResult ShowNotFound()
{
    return ShowNotFound("Seite nicht gefunden....");
}

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

protected ActionResult ShowServerError()
{
    return ShowServerError("Anwendungsfehler....");
}

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

protected ActionResult ShowNotAuthorized()
{
    return ShowNotAuthorized("Sie sind nicht berechtigt ....");

}

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 - Nicht gefunden";
            break;
        case HttpStatusCode.Forbidden:
            title = "403 - Zugriff verweigert";
            break;
        default:
            title = "500 - Anwendungsfehler";
            break;
    }
    ViewBag.Title = title;
    ViewBag.Message = message;
    return View("CustomError");
}

4. Fügen Sie die CustomError.cshtml in Ihren Shared Ansichtenordner. Hier ist mein Beispiel;

@ViewBag.Title

@ViewBag.Message

Jetzt können Sie in Ihrem Anwendungscontroller etwas Ähnliches tun;

public class WidgetsController : ControllerBase
{
  [HttpGet]
  public ActionResult Edit(int id)
  {
    Versuchen
    {
       var widget = db.getWidgetById(id);
       if(widget == null)
          return ShowNotFound();
          //oder return ShowNotFound("Ungültiges Widget!");
       return View(widget);
    }
    fangen(Ausnahme ex)
    {
       //Fehler protokollieren
       logger.Error(ex)
       return ShowServerError();
    }
  }
}

Jetzt zum Hinweis. Es werden keine Fehler bei statischen Dateifehlern behandelt. Wenn Sie also eine Route wie example.com/widgets haben und der Benutzer sie in example.com/widgets.html ändert, erhalten sie die standardmäßige IIS-Fehlerseite, sodass Sie Fehler auf IIS-Ebene auf andere Weise behandeln müssen.

2voto

DarthVader Punkte 49125

Versuchen Sie NotFoundMVC auf Nuget. Es funktioniert, kein Setup erforderlich.

0 Stimmen

http://localhost/Views/Shared/NotFound.cshtml führt nicht zu einer benutzerdefinierten 404-Seite.

0 Stimmen

Es ist sehr einfach anpassbar. Sie haben Zugriff auf die angeforderte URL und den Referrer, so dass Sie tun können, was Sie möchten. Ich benutze dieses Paket und es funktioniert wirklich gut.

0 Stimmen

Dies ist ein großartiges Paket, vorausgesetzt, Sie verwenden keine async Task Aktionen (oder andere ähnliche async) Aktionen. Auf MVC 5 ist dies ein fehlerhaftes Szenario. Es gibt eine Fork auf GitHub, um das zu umgehen, aber für mich ist das ein Nein, nein.

2voto

Red Taz Punkte 3989

Es scheint mir, dass die standardmäßige CustomErrors Konfiguration eigentlich funktionieren sollte, jedoch aufgrund der Abhängigkeit von Server.Transfer scheint es, dass die interne Implementierung von ResponseRewrite nicht mit MVC kompatibel ist.

Dies scheint mir ein offensichtliches Funktionsloch zu sein, also habe ich beschlossen, dieses Feature mithilfe eines HTTP-Moduls neu zu implementieren. Die folgende Lösung ermöglicht es Ihnen, mit jedem gültigen MVC-Route umzugehen, unabhängig vom HTTP-Statuscode (einschließlich 404), genau wie Sie es normalerweise tun würden.

Dies wurde auf den folgenden Plattformen getestet;

  • MVC4 im integrierten Pipeline-Modus (IIS Express 8)
  • MVC4 im klassischen Modus (VS-EntwicklungsServer, Cassini)
  • MVC4 im klassischen Modus (IIS6)

Vorteile

  • Generische Lösung, die in jedes MVC-Projekt integriert werden kann
  • Ermöglicht die Unterstützung der traditionellen benutzerdefinierten Fehlerkonfiguration
  • Funktioniert sowohl im integrierten Pipeline-Modus als auch im klassischen Modus

Die Lösung

namespace Foo.Bar.Modules {

    /// 
    /// Ermöglicht die Unterstützung des CustomErrors ResponseRewrite-Modus in MVC.
    /// 
    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) {

            // Nur Response-Rewrite-Modus behandeln, Weiterleitungs-Konfiguration ignorieren (wenn es nicht kaputt ist, nicht neu implementieren)
            if (CustomErrors.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite && HttpContext.IsCustomErrorEnabled) {

                int statusCode = HttpContext.Response.StatusCode;

                // Wenn diese Anforderung eine Ausnahme ausgelöst hat, dann den tatsächlichen Statuscode herausfinden
                Exception exception = HttpContext.Error;
                if (exception != null) {
                    // Standardfehlerstatuscode für Anwendungsausnahmen festlegen
                    statusCode = (int)HttpStatusCode.InternalServerError;
                }

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

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

                    Dictionary errorPaths = new Dictionary();

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

                    // Benutzerdefinierten Fehlerpfad für diesen Statuscode finden
                    if (errorPaths.Keys.Contains(statusCode)) {
                        string url = errorPaths[statusCode];

                        // Umleitungen vermeiden
                        if (!HttpContext.Request.Url.AbsolutePath.Equals(VirtualPathUtility.ToAbsolute(url))) {

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

                            HttpContext.Server.ClearError();

                            // Umleitung hier durchführen
                            if (HttpRuntime.UsingIntegratedPipeline) {
                                HttpContext.Server.TransferRequest(url, true);
                            }
                            else {
                                HttpContext.RewritePath(url, false);

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

                            // Den ursprünglichen Statuscode an den Client zurückgeben
                            // (dies funktioniert nicht im integrierten Pipeline-Modus)
                            HttpContext.Response.StatusCode = statusCode;

                        }
                    }

                }

            }

        }

        public void Dispose() {

        }

    }

}

Verwendung

Fügen Sie dies als letztes HTTP-Modul in Ihre web.config ein


Für diejenigen unter Ihnen, die aufpassen, werden Sie feststellen, dass im integrierten Pipeline-Modus dies immer mit HTTP 200 antwortet, aufgrund der Funktionsweise von Server.TransferRequest. Um den richtigen Fehlercode zurückzugeben, verwende ich den folgenden Fehlercontroller.

public class ErrorController : Controller {

    public ErrorController() { }

    public ActionResult Index(int id) {
        // Echten Fehlercode an den Client weitergeben
        HttpContext.Response.StatusCode = id;
        HttpContext.Response.TrySkipIisCustomErrors = true;

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

}

2voto

Konamiman Punkte 48557

Meine Lösung, falls sie für jemanden nützlich sein sollte.

In Web.config:

    ...

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

Fügen Sie eine PageNotFound.cshtml im Shared Ordner hinzu, und das war's.

2 Stimmen

Verursacht dieser Fehler nicht eine 302 Weiterleitung und dann einen Status 200 (OK) an den Client? Sollten sie nicht immer noch einen Status 404 erhalten?

0 Stimmen

@Konamiman Bist du sicher, dass die Zeile in deinem Code so aussehen sollte model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ? Request.Url.OriginalString : url; und nicht model.RequestedUrl = Request.Url.OriginalString.Contains(url) && Request.Url.OriginalString != url ? Request.Url.OriginalString : url; (& statt &&)?

1voto

PussInBoots Punkte 9041

Posting eine Antwort, da mein Kommentar zu lang war...

Es ist sowohl ein Kommentar als auch Fragen zum Einhorn-Post/Antwort:

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

Ich bevorzuge diese Antwort gegenüber den anderen aufgrund ihrer Einfachheit und der Tatsache, dass anscheinend einige Leute bei Microsoft konsultiert wurden. Ich habe jedoch drei Fragen, und wenn sie beantwortet werden können, werde ich diese Antwort als den heiligen Gral aller 404/500 Fehlerantworten im Internet für eine ASP.NET MVC (x) App bezeichnen.

@Pure.Krome

  1. Können Sie Ihre Antwort mit den SEO-Dingen aus den Kommentaren aktualisieren, die von GWB erwähnt wurden (es gab in Ihrer Antwort nie eine Erwähnung davon) - und ?

  2. Können Sie Ihre ASP.NET-Teamkollegen fragen, ob es in Ordnung ist, es so zu machen - es wäre schön, eine Bestätigung zu haben - vielleicht ist es ein großes Nein-Nein, redirectMode und existingResponse auf diese Weise zu ändern, um gut mit SEO zu funktionieren?!

  3. Können Sie nach einem Gespräch mit Ihren Freunden bei Microsoft einige Erläuterungen zu all diesen Dingen hinzufügen (customErrors redirectMode="ResponseRewrite", customErrors redirectMode="ResponseRedirect", httpErrors errorMode="Custom" existingResponse="Replace", ENTFERNEN Sie customErrors VOLLSTÄNDIG, wie von jemandem vorgeschlagen)?

Wie ich sagte, es wäre super, wenn wir Ihre Antwort vollständiger machen könnten, da dies eine ziemlich beliebte Frage mit über 54.000 Ansichten zu sein scheint.

Aktualisierung: Die Einhornantwort führt ein 302 Found und ein 200 OK durch und kann nicht so geändert werden, dass sie nur 404 zurückgibt, indem sie eine Route verwendet. Es muss eine physische Datei sein, was nicht sehr MVC ist. Also gehen wir zu einer anderen Lösung über. Schade, denn dies schien bisher die ultimative MVC-Antwort zu sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X