¿Obtener el controlador y el nombre de la acción desde el controlador?


173

Para nuestra aplicación web, necesito guardar el orden de los elementos recuperados y mostrados según la vista, o para ser precisos, el controlador y la acción que generó la vista (y la identificación del usuario, por supuesto, pero ese no es el punto aquí).

En lugar de dar un identificador yo mismo en cada acción del controlador (para usarlo para una clasificación dependiente de la vista de las salidas DB), pensé que sería más seguro y fácil crear este identificador automáticamente desde el controlador y el método de acción que obtiene llamado desde.

¿Cómo puedo obtener el nombre del controlador y la acción desde el método de acción en un controlador? ¿O necesito reflexión para eso? Supongo que es bastante fácil, gracias de antemano!


1
Reflection le daría el nombre del método que maneja la acción, pero presumiblemente prefiere el nombre de la acción tal como lo devuelve el código de Andrei.
citykid

Básicamente, solo necesito un identificador inequívoco para cada acción que ofrece una vista, por lo que ambas formas harían el trabajo. Pero tienes razón, la respuesta de Andrei es definitivamente más elegante.
Alex

@citykid ¿Hay casos en los que estos difieren de maneras distintas al caso y el sufijo "Controlador" para los nombres de clase?
John

@John, ActionNameAttribute permite que el método ac # tenga cualquier nombre de acción: msdn.microsoft.com/en-us/library/…
citykid el

@citykid Oh, está bien. ¿Es una característica obsoleta dado que puede especificar las rutas con un Routeatributo en el método de acción que recopilo? Además, ¿también es posible cambiar el nombre de los controladores?
John

Respuestas:


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

13
En algunos casos en los que es posible que desee tener el nombre del controlador en el archivo View, puede usar esto.ViewContext.RouteData.Values ​​["controller"]. ToString ();
Amogh Natu

Si va a hacer esto (proporcione la acción y el nombre del controlador), ¿por qué no solo asignarlos directamente?
MetalPhoenix

1
@MetalPhoenix, ¿puedes aclarar un poco de qué caso de uso estás hablando? OP no necesita asignar un controlador o una acción; solo necesitan comprender, de manera genérica, cuáles son el controlador y la acción que se está procesando actualmente.
Andrei

1
En una segunda lectura, ¿es posible que haya entendido mal el fragmento de código aquí? ... ¿Valores ["acción"] donde "acción" es una clave y no el nombre de la acción que se va a sustituir (como "'Pass123' sin las comillas" tipo de cosa)? Es decir: ¿seguiría siendo Valores ["acción"] en lugar de Valores ["yourAction"]?
MetalPhoenix

@MetalPhoenix, exactamente, "acción" literal es una clave, y los valores ["acción"] generarán "CurrentActionName"
Andrei

62

Aquí hay algunos métodos de extensión para obtener esa información (también incluye la 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;
    }
}

Uso:

@Html.Controller();
@Html.Action();
@Html.Id();

1
Mejor y completa solución, gracias Jhon
Umar Abbas

24

Puede ser útil Necesitaba la acción en el constructor del controlador, y aparece en este punto del ciclo de vida de MVC, thisno se ha inicializado, y ControllerContext = null. En lugar de profundizar en el ciclo de vida de MVC y encontrar el nombre de función apropiado para anular, acabo de encontrar la acción en elRequestContext.RouteData .

Pero para hacerlo, como con cualquier HttpContextuso relacionado en el constructor, debe especificar el espacio de nombres completo, porque this.HttpContexttampoco se ha inicializado. Afortunadamente, parece que System.Web.HttpContext.Currentes estático.

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

NOTA: probablemente no sea la forma más compatible de acceder a todas las propiedades en HttpContext, pero para RequestContext y Session parece funcionar bien en mi aplicación.


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


4

Esto es lo que tengo hasta ahora:

var actionName = filterContext.ActionDescriptor.ActionName;
var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;

3

Aquí está la respuesta más simple y práctica para obtener un nombre:

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

O

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

Código de pruebas anteriores con asp.net mvc 5.


2

Agregue esto a su controlador base dentro del método 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;
    }

Implemente sus controladores a Basecontroller

Agregue una vista parcial _Breadcrumb.cshtml y agréguela en todas las páginas requeridas con @ Html.Partial ("_ Breadcrumb")

_Breadcrumb.cshtml

<span>
    <a href="../@ViewData["controllerName"]">
        @ViewData["controllerName"]
    </a> > @ViewData["actionName"]
</span>

(1): ¿Sigue siendo una de las formas más comunes dentro de MVC5? (2) ¿De dónde sacas tu filterContextvariable desde dentro GetDefaults()?
chriszo111

1

Puede obtener el nombre del controlador o el nombre de la acción de la acción como cualquier variable. Son simplemente especiales (controlador y acción) y ya están definidos, por lo que no necesita hacer nada especial para obtenerlos, excepto decirle que los necesita.

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

O puede incluir el controlador, la acción en sus modelos para obtener dos de ellos y sus datos personalizados.

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

1

Esto parece funcionar bien para mí (hasta ahora), también funciona si está utilizando el enrutamiento de atributos.

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

1

Para eliminar la necesidad de ToString()usar la llamada

string actionName = ControllerContext.RouteData.GetRequiredString("action");
string controllerName = ControllerContext.RouteData.GetRequiredString("controller");

1

Use líneas dadas en OnActionExecuting para Action y Controller name.

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

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


-8

¿Por qué no tener algo más simple?

Simplemente llame Request.Path, devolverá una cadena separada por "/"

y luego puede usar .Split('/')[1]para obtener el nombre del controlador.

ingrese la descripción de la imagen aquí


1
-1: con su código, las aplicaciones de subnivel simplemente se ignoran (por ejemplo:) http://www.example.com/sites/site1/controllerA/actionB/. MVC proporciona un montón de API para el enrutamiento, entonces, ¿por qué necesita analizar (nuevamente) las URL?
T-moty

¿Por qué reinventar la rueda y, además, con una reinvensión pobre? Esto no funciona para todos los casos.
jstuardo

Además de las subcarpetas, el verdadero problema es que puedes personalizar tus rutas para que no siempre esténcontroller/action
drzaus
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.