Frage Wie gebe ich einen 404-Status zurück, bei dem ungültige Parameter an meinen ASP.NET MVC-Controller übergeben werden?


Ich möchte einen HTTP-Status zurückgeben 404 wenn ungültige Argumente an meinen Controller übergeben werden. Zum Beispiel, wenn ich einen Controller habe, der wie folgt aussieht:

public ActionResult GetAccount(int id)
{
   ...
}

Dann möchte ich eine zurückgeben 404 Wenn solche URLs gefunden werden:

/ GetAccount
/ GetAccount / notanumber

Ich möchte die ArgumentException das ist geworfen.

Ich weiß, dass ich einen NULL-fähigen Typ verwenden könnte:

public ActionResult GetAccount(int? id)
{
  if(id == null) throw new HttpException(404, "Not found");
}

Aber das ist ziemlich eklig und repetitiv.

Ich hatte gehofft, ich könnte dies meinen Controllern bei Bedarf hinzufügen:

[HandleError(View="Error404", ExceptionType = typeof(ArgumentException))]
public class AccountsController : Controller
{
  public ActionResult GetAccount(int id)
  {
    ...
  }
}

Aber das scheint nicht gut zu funktionieren.

ich sah dieser Beitrag und diese Antwort was mein Problem fast löst:

In dieser Antwort eine Zusammenfassung BaseController wird erstellt, von dem Sie alle anderen Controller ableiten:

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
}

Dies funktioniert hervorragend im Umgang mit unbekannten Aktionen mit einem 404 aber erlaubt mir nicht, ungültige Daten als a zu behandeln 404.

Kann ich sicher überschreiben? Controller.OnException(ExceptionContext filterContext) so was:

protected override void OnException(ExceptionContext filterContext)
{
  if(filterContext.Exception.GetType() == typeof(ArgumentException))
  {
    filterContext.ExceptionHandled = true;
    this.InvokeHttp404(filterContext.HttpContext);
  }
  else
  {
    base.OnException(filterContext);
  }
}

Auf der Oberfläche scheint es zu funktionieren, aber speichere ich damit irgendwelche Probleme auf?

Ist das semantisch korrekt?


16
2018-01-24 03:34


Ursprung


Antworten:


Bester Weg? Aktionsarten-Selektor-Attribut!

Um NULL-Argumente zu vermeiden, schlage ich vor, dass Sie eine schreiben Aktion Methodenauswahl Attribut, das nur dann zu Ihrer Aktionsmethode passt id ist versorgt. Es wird nicht gesagt, dass das Argument nicht geliefert wurde, aber dass es keine Aktionsmethoden für die gegebene Anfrage finden konnte.

Ich würde diesen Aktionswähler nennen RequireRouteValuesAttribute und würde so funktionieren:

[RequireRouteValues("id")]
public ActionResult GetAccount(int id)
{
    ...
}

Warum ist dies die beste Lösung für Ihr Problem?

Wenn Sie sich Ihren Code ansehen, möchten Sie eine 404 für Aktionen ausgeben, die mit dem Namen übereinstimmen, aber die Parameterbindung fehlgeschlagen ist (entweder weil sie nicht angegeben wurde oder aus einem anderen Grund). Deine Aktion sozusagen erfordert bestimmter Aktionsparameter andernfalls wird ein 404 zurückgegeben.

Wenn also das Attribut action selector hinzugefügt wird, wird die Anforderung für die Aktion hinzugefügt, sodass sie dem Namen (dies wird von MVC angegeben) entspricht und außerdem bestimmte Aktionsparameter erfordert. Wann immer id wird nicht geliefert Diese Aktion wird nicht abgeglichen. Wenn es eine andere Aktion gibt, die übereinstimmt, ist das nicht das Problem, da diese bestimmte Aktion ausgeführt wird. Die Hauptsache ist erfüllt. Die Aktion stimmt nicht mit der ungültigen Routenanforderung überein, und stattdessen wird 404 zurückgegeben.

Da ist eine App Code dafür!

Prüfen mein Blogpost das implementiert diese Art von Attribut, das Sie sofort verwenden können. Es macht genau das, wonach Sie suchen: Es passt nicht zu Ihrer Aktionsmethode, wenn die bereitgestellten Routendaten nicht alle erforderlichen Werte haben.


6
2018-02-06 08:36



Haftungsausschluss: Dies deckt nicht alle Fälle ab

Bei URLs in Ihren Beispielen kann die Rückgabe von 404 in einer einzelnen Zeile erfolgen. Fügen Sie einfach die Routenbeschränkung für hinzu id Parameter.

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index" }, // Parameter defaults
    new { id = @"\d+" } // restrict id to be required and numeric
);

Und das ist alles. Jetzt eine passende URL, die keine hat idoder id ist nicht numerisch, löst automatisch einen nicht gefundenen Fehler aus (für den es viele Möglichkeiten gibt, einen zu verwenden, einen in Ihrem Beispiel, einen anderen mit benutzerdefiniertem HandleErrorAttribute, etc). Und Sie können Nicht-Nullable verwenden int Parameter für Ihre Aktionen.


1
2018-01-24 06:50



Ich habe es geschafft, dass das funktioniert, indem ich diese Route am Ende aller Routen hinzufüge:

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

Hinweis: Zuerst habe ich folgendes getan: Wie kann ich 404 in ASP.NET MVC richtig behandeln?


0
2017-07-31 21:49