Wie kann ich die aktuelle Aktion in einer ASP.NET MVC-Ansicht zurückgeben?

291

Ich wollte auf meiner Masterseite eine CSS-Klasse festlegen, die vom aktuellen Controller und der aktuellen Aktion abhängt. Ich kann über den aktuellen Controller erhalten ViewContext.Controller.GetType().Name, aber wie bekomme ich die aktuelle Aktion (zB Index, Showetc.)?

Buggs
quelle

Antworten:

83

Verwenden Sie die ViewContextund sehen Sie sich die RouteDataSammlung an, um sowohl die Controller- als auch die Aktionselemente zu extrahieren. Ich denke jedoch, dass das Festlegen einer Datenvariablen, die den Anwendungskontext angibt (z. B. "Bearbeitungsmodus" oder "Fehler"), anstelle von Controller / Aktion, die Kopplung zwischen Ihren Ansichten und Controllern verringert.

Tvanfosson
quelle
Sie können Daten im Controller abrufen und zur Anzeige mit DTO übergeben. stackoverflow.com/a/31749391/4293929
MstfAsan
5
Dies darf NICHT die akzeptierte Antwort sein. Sehen Sie stattdessen die am häufigsten gewählte Antwort.
Hakan Fıstık
1
@HakamFostok Ich denke immer noch, dass der Ratschlag, dem Modell semantische Informationen hinzuzufügen, in allen Fällen eine bessere Methode ist, als sich aus Ihrer Sicht auf Routendaten (Controller, Aktion) zu verlassen, selbst wenn die andere Antwort detailliertere Informationen zum Abrufen dieser Daten enthält.
Tvanfosson
467

Im RC können Sie auch Routendaten wie den Namen der Aktionsmethode wie folgt extrahieren

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

Update für MVC 3

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

Update für MVC 4

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

Update für MVC 4.5

ViewContext.RouteData.Values["action"]
ViewContext.RouteData.Values["controller"]
ViewContext.RouteData.Values["id"]
Christian Dalager
quelle
20
Ich weiß, dass dies V2 datiert, aber es ist jetzt ViewContext.Controller.ValueProvider.GetValue("action").RawValue+ Variationen
Chris S
7
Diese Syntax funktioniert in V4: (Zeichenfolge) ViewContext.RouteData.Values ​​["action"];
Kiprainey
2
Diese Lösung funktioniert bei mir nicht (MVC4 + .NET Framework 4.5.1). Für mich funktioniert die Antwort von Viacheslav Smityukh: ViewContext.RouteData.Values ​​["action"], ViewContext.RouteData.Values ​​["controller"], ViewContext.RouteData.Values ​​["id"],
Tomas Kubes
@ Kiprainey Auch in V3.5: msdn.microsoft.com/en-us/library/…
Pluto
2
Versuchen Sie: (Zeichenfolge) HttpContext.Request.RequestContext.RouteData.Values ​​["action"];
Martin Dawson
60

So erhalten Sie die aktuelle ID in einer Ansicht:

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

So erhalten Sie den aktuellen Controller:

ViewContext.RouteData.Values["controller"].ToString() 
tsquillario
quelle
1
ViewContext.RouteData.Values ​​[<key>] .ToString () löst eine Ausnahme aus, wenn der Wert in RouteData
Grizzly Peak Software
@ShaneLarson Vergleichen Sie einfach mit null oder überprüfen Sie ViewContext.RouteData.Values.ContainsKey(<key>)zuerst mit.
Pluto
40

Ich weiß, dass dies eine ältere Frage ist, aber ich habe sie gesehen und dachte, Sie könnten an einer alternativen Version interessiert sein, als Ihre Ansicht die Daten abrufen zu lassen, die sie für ihre Arbeit benötigt.

Meiner Meinung nach wäre es einfacher, die OnActionExecuting- Methode zu überschreiben . Sie erhalten den ActionExecutingContext , der das ActionDescriptor- Mitglied enthält, mit dem Sie die gesuchten Informationen abrufen können. Dies ist der ActionName. Sie können auch den ControllerDescriptor erreichen und er enthält den 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.
}

Hoffe das hilft. Wenn überhaupt, wird es zumindest eine Alternative für alle anderen zeigen, die von Ihrer Frage kommen.

Dale Ragan
quelle
nette Empfehlung; half mir bei der intelligenten Implementierung von Controller / Action Sensing. Vielen Dank!
Effkay
Den Action-Desrciptor zu bekommen ist das, was ich brauchte. Ich konnte keine andere Lösung finden, also mache ich es einfach hier und schiebe dann, was ich will, in den Viewbag.
Chris Marisic
17

Ich sah verschiedene Antworten und fand einen Klassenhelfer:

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

In View (oder Master / Layout) können Sie es also wie folgt verwenden (Razor-Syntax):

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

Ich hoffe es hilft.

Michael Vashchinsky
quelle
15

Sie können diese Daten aus RouteData eines ViewContext abrufen

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

In MVC sollten Sie der Ansicht alle Daten zur Verfügung stellen und nicht zulassen, dass die Ansicht ihre eigenen Daten sammelt. Sie können also die CSS-Klasse in Ihrer Controller-Aktion festlegen.

ViewData["CssClass"] = "bold";

und wählen Sie diesen Wert aus Ihren ViewData in Ihrer Ansicht aus

Terjetyl
quelle
Dies wäre auch meine bevorzugte Methode, um zu verhindern, dass die Ansichten von der Controller-Struktur abhängen, aber es kann auch anders gemacht werden.
Tvanfosson
1
Ich bin mir nicht sicher, ob ich es "CssClass" nennen würde, da dies darauf hindeutet, dass sich die Anzeigelogik in Ihren Controller einschleicht.
Tvanfosson
Einverstanden, mache ich normalerweise so etwas wie "Kontext", so dass es nicht an die Präsentationsebene gebunden ist und nicht kaputt geht, wenn Sie die Ansicht auch umbenennen.
RedFilter
6

Ich stimme für diese 2:

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

und

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

Sie können sowohl den physischen Namen der aktuellen Ansicht als auch die Aktion abrufen, die sie ausgelöst hat. Es kann in partiellen * .acmx-Seiten nützlich sein, den Host-Container zu bestimmen.


quelle
2

Ich verwende ASP.NET MVC 4 und das hat bei mir funktioniert:

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

Erweiterung der Antwort von Dale Ragan , sein Beispiel für die Wiederverwendung, erweitern, erstellen Sie eine ApplicationController-Klasse, die von Controller abgeleitet ist, und lassen Sie alle Ihre anderen Controller von dieser ApplicationController-Klasse und nicht von Controller ableiten.

Beispiel:

public class MyCustomApplicationController : Controller {}

public class HomeController : MyCustomApplicationController {}

Erstellen Sie auf Ihrem neuen ApplicationController eine Eigenschaft namens ExecutingAction mit dieser Signatur:

protected ActionDescriptor ExecutingAction { get; set; }

Weisen Sie dann in der OnActionExecuting-Methode (aus der Antwort von Dale Ragan) dieser Eigenschaft einfach den ActionDescriptor zu, und Sie können jederzeit darauf zugreifen, wenn Sie ihn in einem Ihrer Controller benötigen.

string currentActionName = this.ExecutingAction.ActionName;
RunnerRick
quelle
0

Überschreiben Sie diese Funktion in Ihrem Controller

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