¿Cómo puedo devolver la acción actual en una vista ASP.NET MVC?

291

Quería establecer una clase CSS en mi página maestra, que depende del controlador y la acción actuales. Puedo acceder al controlador actual a través de ViewContext.Controller.GetType().Name, pero ¿cómo obtengo la acción actual (por ejemplo Index, Showetc.)?

buggs
fuente

Respuestas:

83

Use ViewContexty mire la RouteDatacolección para extraer tanto el controlador como los elementos de acción. Pero creo que establecer alguna variable de datos que indique el contexto de la aplicación (por ejemplo, "modo de edición" o "error") en lugar de controlador / acción reduce el acoplamiento entre sus vistas y controladores.

tvanfosson
fuente
puede obtener datos en el controlador y pasarlos para verlos con DTO. stackoverflow.com/a/31749391/4293929
MstfAsan
55
Esta NO debe ser la respuesta aceptada, vea la respuesta más votada en su lugar.
Hakan Fıstık
1
@HakamFostok Sigo pensando que el consejo para agregar información semántica al modelo es un método mejor en todos los casos que confiar en los datos de ruta (controlador, acción) en su opinión, incluso si la otra respuesta proporciona más detalles sobre cómo obtener esos datos.
tvanfosson
467

En el RC también puede extraer datos de ruta como el nombre del método de acción como este

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

Actualización para MVC 3

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

Actualización para MVC 4

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

Actualización para MVC 4.5

ViewContext.RouteData.Values["action"]
ViewContext.RouteData.Values["controller"]
ViewContext.RouteData.Values["id"]
Christian Dalager
fuente
20
Sé que esto es anterior a V2, pero ahora es ViewContext.Controller.ValueProvider.GetValue("action").RawValue+ variaciones
Chris S
77
Esta sintaxis funciona en V4: (string) ViewContext.RouteData.Values ​​["action"];
kiprainey
2
Esta solución no funciona para mí (MVC4 + .NET Framework 4.5.1). Para mí, funciona la respuesta de Viacheslav Smityukh: ViewContext.RouteData.Values ​​["action"], ViewContext.RouteData.Values ​​["controller"], ViewContext.RouteData.Values ​​["id"],
Tomas Kubes
@kiprainey En V3.5 también: msdn.microsoft.com/en-us/library/…
Plutón
2
Pruebe: (string) HttpContext.Request.RequestContext.RouteData.Values ​​["action"];
Martin Dawson
60

Para obtener la identificación actual en una vista:

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

Para obtener el controlador actual:

ViewContext.RouteData.Values["controller"].ToString() 
tsquillario
fuente
1
ViewContext.RouteData.Values ​​[<key>] .ToString () lanza una excepción si el valor no existe en RouteData
Grizzly Peak Software
@ShaneLarson Simplemente compare con nulo o verifique ViewContext.RouteData.Values.ContainsKey(<key>)primero.
Plutón
40

Sé que esta es una pregunta anterior, pero la vi y pensé que podría estar interesado en una versión alternativa que dejar que su vista maneje la recuperación de los datos que necesita para hacer su trabajo.

Una manera más fácil en mi opinión sería anular el método OnActionExecuting . Se le pasa el ActionExecutingContext que contiene el miembro ActionDescriptor que puede usar para obtener la información que está buscando, que es ActionName y también puede comunicarse con ControllerDescriptor y contiene 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.
}

Espero que esto ayude. En todo caso, al menos mostrará una alternativa para cualquier otra persona que surja de su pregunta.

Dale Ragan
fuente
buena recomendación; me ayudó a implementar el controlador / detección de acción de manera inteligente. ¡Gracias!
effkay
Lo que necesitaba era obtener el Desrciptor de acción, no pude encontrar ninguna otra solución, así que solo lo hago aquí y luego guardo lo que quiero en la bolsa de visualización.
Chris Marisic
17

Vi diferentes respuestas y se me ocurrió un ayudante de clase:

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

Entonces, en View (o master / layout) puede usarlo así (sintaxis 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>

Espero eso ayude.

Michael Vashchinsky
fuente
15

Puede obtener estos datos de RouteData de un ViewContext

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

En MVC, debe proporcionar a la Vista todos los datos, no permitir que la Vista recopile sus propios datos, por lo que lo que puede hacer es establecer la clase CSS en la acción de su controlador.

ViewData["CssClass"] = "bold";

y seleccione este valor de su ViewData en su Vista

terjetyl
fuente
Este sería mi método preferido también para evitar que las vistas dependan de la estructura del controlador, pero se puede hacer de otra manera.
tvanfosson
1
No estoy seguro de que lo llamaría "CssClass", ya que parece indicar que la lógica de visualización se está arrastrando en su controlador.
tvanfosson
De acuerdo, generalmente hago algo como "Contexto", por lo que no está vinculado a la capa de presentación y no se rompe si cambia el nombre de la vista.
RedFilter
6

Yo voto por este 2:

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

y

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

Puede recuperar el nombre físico de la vista actual y la acción que lo activó. Puede ser útil en páginas parciales * .acmx para determinar el contenedor del host.


fuente
2

Estoy usando ASP.NET MVC 4, y esto es lo que funcionó para mí:

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

Extendiendo la respuesta de Dale Ragan , su ejemplo para la reutilización, cree una clase ApplicationController que se derive de Controller y, a su vez, haga que todos sus otros controladores se deriven de esa clase ApplicationController en lugar de Controller.

Ejemplo:

public class MyCustomApplicationController : Controller {}

public class HomeController : MyCustomApplicationController {}

En su nuevo ApplicationController, cree una propiedad llamada ExecutingAction con esta firma:

protected ActionDescriptor ExecutingAction { get; set; }

Y luego, en el método OnActionExecuting (de la respuesta de Dale Ragan), simplemente asigne el ActionDescriptor a esta propiedad y podrá acceder a él cuando lo necesite en cualquiera de sus controladores.

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

Anular esta función en su controlador

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