Comment puis-je retourner l'action en cours dans une vue ASP.NET MVC?

291

Je voulais définir une classe CSS dans ma page maître, qui dépend du contrôleur et de l'action actuels. Je peux accéder au contrôleur actuel via ViewContext.Controller.GetType().Name, mais comment puis-je obtenir l'action en cours (par exemple Index, Showetc.)?

buggs
la source

Réponses:

83

Utilisez le ViewContextet regardez la RouteDatacollection pour extraire à la fois le contrôleur et les éléments d'action. Mais je pense que la définition d'une variable de données qui indique le contexte de l'application (par exemple, "mode d'édition" ou "erreur") plutôt que contrôleur / action réduit le couplage entre vos vues et les contrôleurs.

tvanfosson
la source
vous pouvez obtenir des données dans le contrôleur et les transmettre à DTO. stackoverflow.com/a/31749391/4293929
MstfAsan
5
cela ne doit PAS être la réponse acceptée, voir la réponse la plus votée à la place.
Hakan Fıstık
1
@HakamFostok Je pense toujours que le conseil d'ajouter des informations sémantiques au modèle est une meilleure méthode dans tous les cas que de s'appuyer sur les données de route (contrôleur, action) à votre avis même si l'autre réponse fournit plus de détails sur la façon d'obtenir ces données.
tvanfosson
467

Dans le RC, vous pouvez également extraire des données d'itinéraire comme le nom de la méthode d'action comme ceci

ViewContext.Controller.ValueProvider["action"].RawValue
ViewContext.Controller.ValueProvider["controller"].RawValue
ViewContext.Controller.ValueProvider["id"].RawValue

Mise à jour pour MVC 3

ViewContext.Controller.ValueProvider.GetValue("action").RawValue
ViewContext.Controller.ValueProvider.GetValue("controller").RawValue
ViewContext.Controller.ValueProvider.GetValue("id").RawValue

Mise à jour pour MVC 4

ViewContext.Controller.RouteData.Values["action"]
ViewContext.Controller.RouteData.Values["controller"]
ViewContext.Controller.RouteData.Values["id"]

Mise à jour pour MVC 4.5

ViewContext.RouteData.Values["action"]
ViewContext.RouteData.Values["controller"]
ViewContext.RouteData.Values["id"]
Christian Dalager
la source
20
Je connais cette pré-date V2, mais c'est maintenant ViewContext.Controller.ValueProvider.GetValue("action").RawValue+ variations
Chris S
7
Cette syntaxe fonctionne en V4: (chaîne) ViewContext.RouteData.Values ​​["action"];
kiprainey
2
Cette solution ne fonctionne pas pour moi (MVC4 + .NET Framework 4.5.1). Pour moi, cela fonctionne la réponse de Viacheslav Smityukh: ViewContext.RouteData.Values ​​["action"], ViewContext.RouteData.Values ​​["controller"], ViewContext.RouteData.Values ​​["id"],
Tomas Kubes
@kiprainey Dans V3.5 aussi: msdn.microsoft.com/en-us/library/…
Pluton
2
Essayez: (chaîne) HttpContext.Request.RequestContext.RouteData.Values ​​["action"];
Martin Dawson
60

Pour obtenir l'ID actuel sur une vue:

ViewContext.RouteData.Values["id"].ToString()

Pour obtenir le contrôleur actuel:

ViewContext.RouteData.Values["controller"].ToString() 
tsquillario
la source
1
ViewContext.RouteData.Values ​​[<key>] .ToString () lève une exception si la valeur n'existe pas dans RouteData
Grizzly Peak Software
@ShaneLarson Il suffit de comparer avec null ou de vérifier en ViewContext.RouteData.Values.ContainsKey(<key>)premier.
Pluton
40

Je sais que c'est une question plus ancienne, mais je l'ai vue et j'ai pensé que vous pourriez être intéressé par une version alternative que de laisser votre vue gérer la récupération des données dont elle a besoin pour faire son travail.

Un moyen plus simple à mon avis serait de remplacer la méthode OnActionExecuting . Vous passez le ActionExecutingContext qui contient le membre ActionDescriptor que vous pouvez utiliser pour obtenir les informations que vous recherchez, qui est le ActionName et vous pouvez également atteindre le ControllerDescriptor et il contient le ControllerName.

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    ActionDescriptor actionDescriptor = filterContext.ActionDescriptor;
    string actionName = actionDescriptor.ActionName;
    string controllerName = actionDescriptor.ControllerDescriptor.ControllerName;
    // Now that you have the values, set them somewhere and pass them down with your ViewModel
    // This will keep your view cleaner and the controller will take care of everything that the view needs to do it's job.
}

J'espère que cela t'aides. Si quoi que ce soit, au moins cela montrera une alternative pour toute autre personne qui vient par votre question.

Dale Ragan
la source
belle recommandation; m'a aidé à implémenter intelligemment le contrôleur / la détection d'action. Merci!
effkay
Obtenir le descripteur d'action était ce dont j'avais besoin, je ne pouvais pas vraiment trouver d'autre solution, alors je le fais ici et je mets ce que je veux dans le sac de vision.
Chris Marisic
17

J'ai vu différentes réponses et j'ai trouvé un assistant de classe:

using System;
using System.Web.Mvc;

namespace MyMvcApp.Helpers {
    public class LocationHelper {
        public static bool IsCurrentControllerAndAction(string controllerName, string actionName, ViewContext viewContext) {
            bool result = false;
            string normalizedControllerName = controllerName.EndsWith("Controller") ? controllerName : String.Format("{0}Controller", controllerName);

            if(viewContext == null) return false;
            if(String.IsNullOrEmpty(actionName)) return false;

            if (viewContext.Controller.GetType().Name.Equals(normalizedControllerName, StringComparison.InvariantCultureIgnoreCase) &&
                viewContext.Controller.ValueProvider.GetValue("action").AttemptedValue.Equals(actionName, StringComparison.InvariantCultureIgnoreCase)) {
                result = true;
            }

            return result;
        }
    }
}

Donc, dans View (ou master / layout), vous pouvez l'utiliser comme ça (syntaxe Razor):

            <div id="menucontainer">

                <ul id="menu">
                    <li @if(MyMvcApp.Helpers.LocationHelper.IsCurrentControllerAndAction("home", "index", ViewContext)) {
                            @:class="selected"
                        }>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li @if(MyMvcApp.Helpers.LocationHelper.IsCurrentControllerAndAction("account","logon", ViewContext)) {
                            @:class="selected"
                        }>@Html.ActionLink("Logon", "Logon", "Account")</li>
                    <li @if(MyMvcApp.Helpers.LocationHelper.IsCurrentControllerAndAction("home","about", ViewContext)) {
                            @:class="selected"
                        }>@Html.ActionLink("About", "About", "Home")</li>
                </ul>

            </div>

J'espère que ça aide.

Michael Vashchinsky
la source
15

Vous pouvez obtenir ces données de RouteData d'un ViewContext

ViewContext.RouteData.Values["controller"]
ViewContext.RouteData.Values["action"]
Viacheslav Smityukh
la source
9

Dans MVC, vous devez fournir à la vue toutes les données, ne pas laisser la vue collecter ses propres données, vous pouvez donc définir la classe CSS dans l'action de votre contrôleur.

ViewData["CssClass"] = "bold";

et sélectionnez cette valeur de vos ViewData dans votre vue

terjetyl
la source
Ce serait également ma méthode préférée pour empêcher les vues de dépendre de la structure du contrôleur, mais cela peut être fait autrement.
tvanfosson
1
Je ne suis pas sûr de le nommer "CssClass" car cela semble indiquer que la logique d'affichage se glisse dans votre contrôleur.
tvanfosson
D'accord, je fais généralement quelque chose comme "Context", donc il n'est pas lié à la couche de présentation et ne se casse pas si vous renommez la vue non plus.
RedFilter
6

Je vote pour ce 2:

string currentActionName = ViewContext.RouteData.GetRequiredString("action");

et

string currentViewName = ((WebFormView)ViewContext.View).ViewPath;

Vous pouvez récupérer le nom physique de la vue actuelle et l'action qui l'a déclenchée. Il peut être utile dans les pages partielles * .acmx pour déterminer le conteneur hôte.


la source
2

J'utilise ASP.NET MVC 4, et c'est ce qui a fonctionné pour moi:

ControllerContext.Controller.ValueProvider.GetValue("controller").RawValue
ControllerContext.Controller.ValueProvider.GetValue("action").RawValue
kiewic
la source
0

Prolonger la réponse de Dale Ragan , son exemple de réutilisation, créez une classe ApplicationController qui dérive de Controller, et à votre tour, tous vos autres contrôleurs dérivent de cette classe ApplicationController plutôt que Controller.

Exemple:

public class MyCustomApplicationController : Controller {}

public class HomeController : MyCustomApplicationController {}

Sur votre nouveau ApplicationController, créez une propriété nommée ExecutingAction avec cette signature:

protected ActionDescriptor ExecutingAction { get; set; }

Et puis dans la méthode OnActionExecuting (d'après la réponse de Dale Ragan), affectez simplement l'ActionDescriptor à cette propriété et vous pouvez y accéder chaque fois que vous en avez besoin dans l'un de vos contrôleurs.

string currentActionName = this.ExecutingAction.ActionName;
RunnerRick
la source
0

Remplacez cette fonction dans votre contrôleur

protected override void HandleUnknownAction(string actionName) 
{  TempData["actionName"] = actionName;
   View("urViewName").ExecuteResult(this.ControllerContext);
}
Santosh Pandey
la source