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.

14voto

Dave Lowe Punkte 343

Ich mag die Lösung von cottsak wirklich und finde sie sehr klar erklärt. Meine einzige Ergänzung bestand darin, Schritt 2 wie folgt zu ändern

public abstract class MyController : Controller
{

    #region Http404-Behandlung

    protected override void HandleUnknownAction(string actionName)
    {
        // Wenn der Controller ein ErrorController ist, keine Ausnahmen 'verschachteln'
        if (this.GetType() != typeof(ErrorController))
            this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance();
        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
}

Im Wesentlichen wird dadurch verhindert, dass URLs mit ungültigen Aktionen UND Controllern zweimal das Ausnahme-Routine auslösen. Z.B. für URLs wie asdfsdf/dfgdfgd

4 Stimmen

Das ist ausgezeichnet. Diese "zweimal" Fälle fingen an, mich zu stören. meine Antwort aktualisiert

0 Stimmen

Funktioniert die obige Lösung überhaupt, wenn der Benutzer einen falschen Controller- oder Aktionsnamen eingibt?

7voto

Dave K Punkte 757

Der einzige Weg, wie ich @cottsaks Methode zum Funktionieren für ungültige Controller bekommen konnte, war die vorhandene Routenanforderung in der CustomControllerFactory wie folgt zu ändern:

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

Ich sollte erwähnen, dass ich MVC 2.0 verwende.

0 Stimmen

Weißt du warum? (spezifisch für MVC2?)

0 Stimmen

Ich glaube, der Schlüssel bestand darin, die vorhandene Anfrage zu ändern, anstatt eine neue zu erstellen, aber ich habe das vor einer Weile gemacht, also bin ich mir nicht sicher, ob das es war. Das "InvokeHttp404" hat nicht funktioniert von der Controller Factory aus.

0 Stimmen

Ich habe meine Antwort heute mit einigen MVC2-spezifischen Details aktualisiert. Können Sie mir bitte mitteilen, ob meine Lösung, wie oben beschrieben, immer noch nicht für Sie funktioniert?

5voto

sky-dev Punkte 6050

Hier ist eine weitere Methode unter Verwendung von MVC-Tools, mit der Sie Anforderungen an falsche Controller-Namen, falsche Routen-Namen und alle anderen Kriterien, die Sie innerhalb einer Aktionsmethode für angemessen halten, behandeln können. Persönlich ziehe ich es vor, so viele web.config-Einstellungen wie möglich zu vermeiden, da sie die 302 / 200 Weiterleitung durchführen und keine ResponseRewrite (Server.Transfer) unter Verwendung von Razor-Ansichten unterstützen. Ich ziehe es vor, aus SEO-Gründen eine 404 mit einer benutzerdefinierten Fehlerseite zurückzugeben.

Einige davon sind eine neue Ansicht von cottsaks Technik oben.

Diese Lösung verwendet auch minimale web.config-Einstellungen zugunsten der MVC 3 Error-Filter.

Verwendung

Werfen Sie einfach eine HttpException von einer Aktion oder einer benutzerdefinierten ActionFilterAttribute.

Throw New HttpException(HttpStatusCode.NotFound, "[Benutzerdefinierte Fehlermeldung hier]")

Schritt 1

Fügen Sie die folgende Einstellung Ihrer web.config hinzu. Dies ist erforderlich, um den HandleErrorAttribute von MVC zu verwenden.

Schritt 2

Fügen Sie einen benutzerdefinierten HandleHttpErrorAttribute ähnlich dem HandleErrorAttribute des MVC-Frameworks hinzu, jedoch für HTTP-Fehler:

Public Class HandleHttpErrorAttribute
    Inherits FilterAttribute
    Implements IExceptionFilter

    ...

... (weitere Übersetzungen für Schritt 3 bis Schritt 6 und Zusammenfassung werden fortgesetzt)

0 Stimmen

Hmm, ich konnte das nicht zum Laufen bringen: Die IControllerFactory 'aaa.bbb.CustomControllerFactory' hat keinen Controller für den Namen '123' zurückgegeben. - Irgendwelche Ideen, warum ich das bekommen würde?

0 Stimmen

RedirectMode="ResponseRedirect". Dies wird ein 302 Found + ein 200 OK zurückgeben, was nicht gut für das SEO ist!

5voto

Herman Kan Punkte 2115

Meine verkürzte Lösung, die mit unbehandelten Bereichen, Controllern und Aktionen funktioniert:

  1. Erstellen Sie eine Ansicht 404.cshtml.

  2. Erstellen Sie eine Basisklasse für Ihre Controller:

    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. Erstellen Sie eine benutzerdefinierte Controller Factory, die Ihren Basiskontroller als Fallback zurückgibt:

    public class ControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (controllerType != null)
                return base.GetControllerInstance(requestContext, controllerType);
    
            return new Controller();
        }
    }
  4. Fügen Sie Application_Start() die folgende Zeile hinzu:

    ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));

4voto

Diganta Kumar Punkte 3569

Im MVC4 WebAPI kann 404 auf folgende Weise verarbeitet werden,

COURSES APICONTROLLER

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

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

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

        return resp;
    }

HOME CONTROLLER

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

VIEW

    var id = @Model;
    var course = $('#course');
    $.ajax({    
        url: '/api/courses/' + id,
        success: function (data) {
            course.text(data.Name);
        },
        statusCode: {
            404: function() 
            {
                course.text('Kurs nicht verfügbar!');    
            }
        }
    });

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

ERGEBNISSE

Bildbeschreibung hier eingeben

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