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

Alex
fuente
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();
Andrei
fuente
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();
John Bubriski
fuente
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.

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

Esto es lo que tengo hasta ahora:

var actionName = filterContext.ActionDescriptor.ActionName;
var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
usuario3563149
fuente
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.

Matheus Miranda
fuente
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>
Kurkula
fuente
(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;
    }
MstfAsan
fuente
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");
    }
}
joepour
fuente
1

Para eliminar la necesidad de ToString()usar la llamada

string actionName = ControllerContext.RouteData.GetRequiredString("action");
string controllerName = ControllerContext.RouteData.GetRequiredString("controller");
Vadim Ovchinnikov
fuente
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 ();

Bilal Raj
fuente
-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í

adie wong
fuente
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