Obtenir le nom du contrôleur et de l'action depuis le contrôleur?

173

Pour notre application Web, je dois enregistrer l'ordre des éléments récupérés et affichés en fonction de la vue - ou pour être précis - du contrôleur et de l'action qui ont généré la vue (et l'ID utilisateur bien sûr, mais ce n'est pas le point ici).

Au lieu de simplement donner un identifiant moi-même dans chaque action du contrôleur (afin de l'utiliser pour un tri des sorties DB en fonction de la vue), j'ai pensé qu'il serait plus sûr et plus facile de créer cet identifiant automatiquement à partir du contrôleur et de la méthode d'action qu'il obtient appelé de.

Comment puis-je obtenir le nom du contrôleur et l'action à partir de la méthode d'action dans un contrôleur? Ou ai-je besoin de réflexion pour cela? Je suppose que c'est assez facile, merci d'avance!

Alex
la source
1
Reflection vous donnera le nom de la méthode qui gère l'action, mais vous préférez probablement le nom de l'action tel que renvoyé par le code d'Andrei.
citykid
J'ai simplement besoin d'un identifiant sans ambiguïté pour chaque action qui fournit une vue, donc les deux façons feraient le travail. Mais vous avez raison, la réponse d'Andrei est nettement plus élégante.
Alex
@citykid Y a-t-il des cas où ceux-ci diffèrent par des manières autres que la casse et le suffixe "Controller" pour les noms de classe?
John
@John, ActionNameAttribute permet à la méthode ac # d'avoir n'importe quel nom d'action: msdn.microsoft.com/en-us/library/…
citykid
@citykid Oh, d'accord. C'est une sorte de fonctionnalité obsolète étant donné que vous pouvez spécifier les routes avec un Routeattribut sur la méthode d'action que je rassemble? Est-il également possible de renommer les contrôleurs?
John

Réponses:

345
string actionName = this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();
Andrei
la source
13
Dans certains cas où vous voudrez peut-être avoir le nom du contrôleur dans le fichier View, vous pouvez simplement utiliser this.ViewContext.RouteData.Values ​​["controller"]. ToString ();
Amogh Natu
Si vous allez faire cela (indiquez l'action et le nom du contrôleur), pourquoi ne pas les attribuer directement ???
MetalPhoenix
1
@MetalPhoenix, pouvez-vous clarifier un peu de quel cas d'utilisation vous parlez? OP n'a pas besoin d'attribuer un contrôleur ou une action - ils ont juste besoin de comprendre, de manière générique, quels sont le contrôleur et l'action en cours de traitement.
Andrei
1
Lors d'une deuxième lecture, est-il possible que j'ai mal compris l'extrait de code ici? ... Valeurs ["action"] où "action" est une clé et non le nom de l'action à remplacer (comme le type de chose "'Pass123' sans les guillemets")? C'est-à-dire: serait toujours Valeurs ["action"] au lieu de Valeurs ["yourAction"]?
MetalPhoenix
@MetalPhoenix, exactement, "action" littéral est une clé, et Values ​​["action"] affichera "CurrentActionName"
Andrei
62

Voici quelques méthodes d'extension pour obtenir ces informations (elles incluent également l'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;
    }
}

Usage:

@Html.Controller();
@Html.Action();
@Html.Id();
John Bubriski
la source
1
Meilleure solution complète, merci Jhon
Umar Abbas
24

Cela pourrait être utile. J'avais besoin de l'action dans le constructeur du contrôleur, et il apparaît à ce stade du cycle de vie MVC, thisn'a pas été initialisé et ControllerContext = null. Au lieu de fouiller dans le cycle de vie MVC et de trouver le nom de fonction approprié à remplacer, je viens de trouver l'action dans le fichier RequestContext.RouteData.

Mais pour ce faire, comme pour toute HttpContextutilisation associée dans le constructeur, vous devez spécifier l'espace de noms complet, car this.HttpContextil n'a pas non plus été initialisé. Heureusement, il semble System.Web.HttpContext.Currentstatique.

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

REMARQUE: ce n'est probablement pas le moyen le plus pris en charge pour accéder à toutes les propriétés de HttpContext, mais pour RequestContext et Session, il semble fonctionner correctement dans mon application.

sonjz
la source
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
la source
5
 @this.ViewContext.RouteData.Values["controller"].ToString();
Hossein Hajizadeh
la source
4

Voici ce que j'ai jusqu'à présent:

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

Voici la réponse la plus simple et la plus pratique pour obtenir un nom:

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

Ou

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

Le code ci-dessus teste avec asp.net mvc 5.

Matheus Miranda
la source
2

Ajoutez ceci à votre contrôleur de base dans la méthode GetDefaults ()

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

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

Implémentez vos contrôleurs dans Basecontroller

Ajoutez une vue partielle _Breadcrumb.cshtml et ajoutez-la dans toutes les pages requises avec @ Html.Partial ("_ Breadcrumb")

_Breadcrumb.cshtml

<span>
    <a href="../@ViewData["controllerName"]">
        @ViewData["controllerName"]
    </a> > @ViewData["actionName"]
</span>
Kurkula
la source
(1): Est-ce toujours l'un des moyens les plus courants dans MVC5? (2) D'où tirez-vous votre filterContextvariable de l'intérieur GetDefaults()?
chriszo111
1

Vous pouvez obtenir le nom du contrôleur ou le nom de l'action à partir de l'action comme n'importe quelle variable. Ils sont juste spéciaux (contrôleur et action) et déjà définis, vous n'avez donc rien à faire de spécial pour les obtenir, sauf en vous disant que vous en avez besoin.

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

Ou vous pouvez inclure un contrôleur, une action dans vos modèles pour en obtenir deux et vos données personnalisées.

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
la source
1

Cela semble bien fonctionner pour moi (jusqu'à présent), fonctionne également si vous utilisez le routage d'attributs.

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
la source
1

Pour supprimer le besoin d' ToString()utiliser l'appel

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

Utilisez les lignes données dans OnActionExecuting pour l'action et le nom du contrôleur.

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

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

Bilal Raj
la source
-8

Pourquoi ne pas avoir quelque chose de plus simple?

Appelez simplement Request.Path, il renverra une chaîne séparée par le "/"

puis vous pouvez utiliser .Split('/')[1]pour obtenir le nom du contrôleur.

entrez la description de l'image ici

adie wong
la source
1
-1: avec votre code, les applications de sous-niveau sont simplement ignorées (ex:) http://www.example.com/sites/site1/controllerA/actionB/. MVC fournit un tas d'API pour le routage, alors pourquoi avez-vous besoin d'analyser (à nouveau) les URL?.
T-moty
Pourquoi réinventer la roue et en plus, avec une mauvaise réinvention? cela ne fonctionne pas dans tous les cas.
jstuardo
à part les sous-dossiers, le vrai problème est que vous pouvez personnaliser vos itinéraires pour qu'ils ne le soient pas toujourscontroller/action
drzaus