Controller und Aktionsname innerhalb des Controllers abrufen?

173

Für unsere Webanwendung muss ich die Reihenfolge der abgerufenen und angezeigten Elemente in Abhängigkeit von der Ansicht - oder genauer gesagt - dem Controller und der Aktion, die die Ansicht generiert haben (und natürlich der Benutzer-ID, aber das ist hier nicht der Punkt) speichern.

Anstatt in jeder Controller-Aktion selbst einen Bezeichner anzugeben (um ihn für eine ansichtsabhängige Sortierung von DB-Ausgaben zu verwenden), hielt ich es für sicherer und einfacher, diesen Bezeichner automatisch aus dem Controller und der Aktionsmethode zu erstellen, die er erhält angerufen von.

Wie kann ich den Namen des Controllers und der Aktion innerhalb der Aktionsmethode in einem Controller abrufen? Oder brauche ich dafür Reflexion? Ich denke, es ist ziemlich einfach, danke im Voraus!

Alex
quelle
1
Reflection würde Ihnen den Methodennamen geben, der die Aktion behandelt, aber vermutlich bevorzugen Sie den Aktionsnamen, wie er von Andrei's Code zurückgegeben wird.
Citykid
Ich brauche im Grunde nur eine eindeutige Kennung für jede Aktion, die eine Ansicht liefert, also würden beide Wege die Arbeit erledigen. Aber du hast recht, Andrei's Antwort ist definitiv eleganter.
Alex
@citykid Gibt es Fälle, in denen sich diese auf andere Weise als case und das Suffix "Controller" für Klassennamen unterscheiden?
John
@ John, ActionNameAttribute erlaubt der ac # -Methode, einen beliebigen Aktionsnamen zu haben: msdn.microsoft.com/en-us/library/…
citykid
@citykid Oh, ok. Das ist eine veraltete Funktion, da Sie die Routen mit einem RouteAttribut für die von mir erfasste Aktionsmethode angeben können . Ist es auch möglich, Controller umzubenennen?
John

Antworten:

345
string actionName = this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();
Andrei
quelle
13
In einigen Fällen, in denen Sie den Namen des Controllers in der View-Datei haben möchten, können Sie einfach this.ViewContext.RouteData.Values ​​["controller"] verwenden. ToString ();
Amogh Natu
Wenn Sie dies tun (geben Sie den Aktions- und Controller-Namen an), warum weisen Sie sie nicht einfach direkt zu?
MetalPhoenix
1
@MetalPhoenix, können Sie ein wenig klären, über welchen Anwendungsfall Sie sprechen? OP muss keine Steuerung oder Aktion zuweisen - sie müssen lediglich allgemein verstehen, welche Steuerung und Aktion gerade verarbeitet werden.
Andrei
1
Ist es beim zweiten Lesen möglich, dass ich den Code-Snippit hier falsch verstanden habe? ... Werte ["Aktion"], bei denen "Aktion" ein Schlüssel ist und nicht der Name der zu ersetzenden Aktion (wie "'Pass123' ohne Anführungszeichen")? Das heißt: wären immer noch Werte ["Aktion"] anstelle von Werten ["IhreAktion"]?
MetalPhoenix
@MetalPhoenix, genau, "Aktion" Literal ist ein Schlüssel, und Werte ["Aktion"] wird "CurrentActionName"
Andrei
62

Hier sind einige Erweiterungsmethoden zum Abrufen dieser Informationen (sie enthalten auch die ID):

public static class HtmlRequestHelper
{
    public static string Id(this HtmlHelper htmlHelper)
    {
        var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;

        if (routeValues.ContainsKey("id"))
            return (string)routeValues["id"];
        else if (HttpContext.Current.Request.QueryString.AllKeys.Contains("id"))
            return HttpContext.Current.Request.QueryString["id"];

        return string.Empty;
    }

    public static string Controller(this HtmlHelper htmlHelper)
    {
        var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;

        if (routeValues.ContainsKey("controller"))
            return (string)routeValues["controller"];

        return string.Empty;
    }

    public static string Action(this HtmlHelper htmlHelper)
    {
        var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;

        if (routeValues.ContainsKey("action"))
            return (string)routeValues["action"];

        return string.Empty;
    }
}

Verwendung:

@Html.Controller();
@Html.Action();
@Html.Id();
John Bubriski
quelle
1
Beste und vollständige Lösung, danke Jhon
Umar Abbas
24

Könnte nützlich sein. Ich brauchte die Aktion im Konstruktor des Controllers, und sie wird an diesem Punkt des MVC-Lebenszyklus angezeigt, thisnicht initialisiert und ControllerContext = null. Anstatt in den MVC-Lebenszyklus einzutauchen und den geeigneten Funktionsnamen zum Überschreiben zu finden, habe ich die Aktion einfach in der gefunden RequestContext.RouteData.

Dazu müssen Sie jedoch, wie bei allen HttpContextverwandten Verwendungen im Konstruktor, den vollständigen Namespace angeben, da dieser this.HttpContextebenfalls nicht initialisiert wurde. Zum Glück scheint System.Web.HttpContext.Currentes statisch zu sein.

// controller constructor
public MyController() {
    // grab action from RequestContext
    string action = System.Web.HttpContext.Current.Request.RequestContext.RouteData.GetRequiredString("action");

    // grab session (another example of using System.Web.HttpContext static reference)
    string sessionTest = System.Web.HttpContext.Current.Session["test"] as string
}

HINWEIS: Wahrscheinlich nicht die am meisten unterstützte Möglichkeit, auf alle Eigenschaften in HttpContext zuzugreifen, aber für RequestContext und Session scheint dies in meiner Anwendung einwandfrei zu funktionieren.

sonjz
quelle
11
var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;
if (routeValues != null) 
{
    if (routeValues.ContainsKey("action"))
    {
        var actionName = routeValues["action"].ToString();
                }
    if (routeValues.ContainsKey("controller"))
    {
        var controllerName = routeValues["controller"].ToString();
    }
}
Chris Ballance
quelle
5
 @this.ViewContext.RouteData.Values["controller"].ToString();
Hossein Hajizadeh
quelle
4

Das habe ich bisher:

var actionName = filterContext.ActionDescriptor.ActionName;
var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
user3563149
quelle
3

Hier ist die einfachste und praktischste Antwort, um einen Namen zu erhalten:

var actionName = RouteData.Values["action"];
var controllerName = RouteData.Values["controller"];

Oder

string actionName = RouteData.Values["action"].ToString();
string controllerName = RouteData.Values["controller"].ToString();

Code über Tests mit asp.net mvc 5.

Matheus Miranda
quelle
2

Fügen Sie dies Ihrem Basis-Controller innerhalb der GetDefaults () -Methode hinzu

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
         GetDefaults();
         base.OnActionExecuting(filterContext);
    }

    private void GetDefaults()
    {
    var actionName = filterContext.ActionDescriptor.ActionName;
    var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
    }

Implementieren Sie Ihre Controller in Basecontroller

Fügen Sie eine Teilansicht _Breadcrumb.cshtml hinzu und fügen Sie sie auf allen erforderlichen Seiten mit @ Html.Partial ("_ Breadcrumb") hinzu.

_Breadcrumb.cshtml

<span>
    <a href="../@ViewData["controllerName"]">
        @ViewData["controllerName"]
    </a> > @ViewData["actionName"]
</span>
Kurkula
quelle
(1): Ist dies immer noch einer der häufigsten Wege in MVC5? (2) Woher bekommen Sie Ihre filterContextVariable von innen GetDefaults()?
Chriszo111
1

Sie können den Controller-Namen oder den Aktionsnamen wie jede Variable aus der Aktion abrufen. Sie sind nur speziell (Controller und Aktion) und bereits definiert, sodass Sie nichts Besonderes tun müssen, um sie zu erhalten, außer zu sagen, dass Sie sie benötigen.

public string Index(string controller,string action)
   {
     var names=string.Format("Controller : {0}, Action: {1}",controller,action);
     return names;
   }

Oder Sie können Controller und Aktionen in Ihre Modelle aufnehmen, um zwei davon und Ihre benutzerdefinierten Daten abzurufen.

public class DtoModel
    {
        public string Action { get; set; }
        public string Controller { get; set; }
        public string Name { get; set; }
    }

public string Index(DtoModel baseModel)
    {
        var names=string.Format("Controller : {0}, Action: {1}",baseModel.Controller,baseModel.Action);
        return names;
    }
MstfAsan
quelle
1

Dies scheint für mich (bisher) gut zu funktionieren, funktioniert auch, wenn Sie Attribut-Routing verwenden.

public class BaseController : Controller
{
    protected string CurrentAction { get; private set; }
    protected string CurrentController { get; private set; }

    protected override void Initialize(RequestContext requestContext)
    {
        this.PopulateControllerActionInfo(requestContext);
    }

    private void PopulateControllerActionInfo(RequestContext requestContext)
    {
        RouteData routedata = requestContext.RouteData;

        object routes;

        if (routedata.Values.TryGetValue("MS_DirectRouteMatches", out routes))
        {
            routedata = (routes as List<RouteData>)?.FirstOrDefault();
        }

        if (routedata == null)
            return;

        Func<string, string> getValue = (s) =>
        {
            object o;
            return routedata.Values.TryGetValue(s, out o) ? o.ToString() : String.Empty;
        };

        this.CurrentAction = getValue("action");
        this.CurrentController = getValue("controller");
    }
}
Joepour
quelle
1

Um die Notwendigkeit eines ToString()Anrufs zu beseitigen , verwenden Sie

string actionName = ControllerContext.RouteData.GetRequiredString("action");
string controllerName = ControllerContext.RouteData.GetRequiredString("controller");
Vadim Ovchinnikov
quelle
1

Verwenden Sie die angegebenen Zeilen in OnActionExecuting für Aktion und den Controllernamen.

Zeichenfolge actionName = this.ControllerContext.RouteData.Values ​​["action"]. ToString ();

Zeichenfolge controllerName = this.ControllerContext.RouteData.Values ​​["controller"]. ToString ();

Bilal Raj
quelle
-8

Warum nicht etwas Einfacheres haben?

Rufen Request.PathSie einfach auf , es wird eine durch "/" getrennte Zeichenfolge zurückgegeben.

und dann können Sie verwenden .Split('/')[1], um den Controller-Namen zu erhalten.

Geben Sie hier die Bildbeschreibung ein

Adie Wong
quelle
1
-1: Mit Ihrem Code werden untergeordnete Anwendungen einfach ignoriert (zB :) http://www.example.com/sites/site1/controllerA/actionB/. MVC bietet eine Reihe von APIs für das Routing. Warum müssen Sie also (erneut) URLs analysieren?.
T-Moty
Warum das Rad neu erfinden und außerdem mit einer schlechten Nachspannung? Dies funktioniert nicht in allen Fällen.
jstuardo
Abgesehen von Unterordnern besteht das eigentliche Problem darin, dass Sie Ihre Routen so anpassen können, dass sie nicht immer controller/action
angezeigt