Obter o nome do controlador e da ação de dentro do controlador?

173

Para nosso aplicativo Web, preciso salvar a ordem dos itens buscados e exibidos, dependendo da visualização - ou, para ser mais preciso - do controlador e da ação que gerou a visualização (e o ID do usuário, é claro, mas esse não é o ponto aqui).

Em vez de apenas me fornecer um identificador em cada ação do controlador (para usá-lo para algumas classificações de saídas de banco de dados dependentes de visualização), pensei que seria mais seguro e fácil criar esse identificador automaticamente a partir do controlador e do método de ação que obtém chamado de.

Como posso obter o nome do controlador e a ação de dentro do método de ação em um controlador? Ou preciso de reflexão para isso? Eu acho que é bem fácil, obrigado desde já!

Alex
fonte
1
O Reflection forneceria o nome do método que lida com a ação, mas presumivelmente você prefere o nome da ação conforme retornado pelo código de Andrei.
Citykid
Basicamente, só preciso de um identificador inequívoco para cada ação que forneça uma exibição, para que os dois lados façam o trabalho. Mas você está certo, a resposta de Andrei é definitivamente mais elegante.
21813 Alex
@citykid Existem casos em que estes diferem de maneiras diferentes de maiúsculas e minúsculas e o sufixo "Controller" para nomes de classes?
John
@ John, ActionNameAttribute permite ac # método para ter qualquer nome da ação: msdn.microsoft.com/en-us/library/...
citykid
@citykid Oh, ok. Esse é um recurso obsoleto, pois você pode especificar as rotas com um Routeatributo no método de ação que eu reunir? Além disso, também é possível renomear controladores?
John

Respostas:

345
string actionName = this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();
Andrei
fonte
13
Em alguns casos, onde você pode querer ter o nome do controlador no arquivo View, basta usar this.ViewContext.RouteData.Values ​​["controller"]. ToString ();
Amogh Natu
Se você fizer isso (forneça o nome da ação e do controlador), por que não atribuí-los diretamente ???
precisa saber é o seguinte
1
@MetalPhoenix, você pode esclarecer um pouco sobre o caso de uso que está falando? O OP não precisa atribuir controlador ou ação - eles apenas precisam entender, de maneira genérica, quais são o controlador e a ação que está sendo processada atualmente.
217 Andrei
1
Em uma segunda leitura, é possível que eu tenha entendido mal o snippit de código aqui? ... Valores ["action"] em que "action" é uma chave e não o nome da ação a ser substituída (como "Pass123 'sem o tipo de coisa entre aspas")? Ou seja: ainda seriam Valores ["ação"] em vez de Valores ["suaAção"]?
precisa saber é o seguinte
@MetalPhoenix, exatamente, "ação" literal é uma chave, e Valores [ "ação"] saída vontade "CurrentActionName"
Andrei
62

Aqui estão alguns métodos de extensão para obter essas informações (também inclui o 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
fonte
1
Melhor e solução completa, obrigado Jhon
Umar Abbas
24

Pode ser útil. Eu precisava da ação no construtor do controlador e ela aparece neste ponto do ciclo de vida do MVC, thisnão foi inicializada e ControllerContext = null. Em vez de investigar o ciclo de vida do MVC e encontrar o nome da função apropriada para substituir, encontrei a ação no RequestContext.RouteData.

Mas, para fazer isso, como em qualquer HttpContextuso relacionado no construtor, você deve especificar o espaço para nome completo, porque this.HttpContexttambém não foi inicializado. Felizmente, parece que System.Web.HttpContext.Currenté 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: provavelmente não é a maneira mais suportada de acessar todas as propriedades no HttpContext, mas para RequestContext e Session parece funcionar bem no meu aplicativo.

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

Isto é o que eu tenho até agora:

var actionName = filterContext.ActionDescriptor.ActionName;
var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
user3563149
fonte
3

Aqui está a resposta mais simples e prática para obter um nome:

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

Ou

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

Codifique os testes acima com o asp.net mvc 5.

Matheus Miranda
fonte
2

Adicione isso ao seu controlador base dentro do 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 seus controladores no controle básico

Adicione uma visualização parcial _Breadcrumb.cshtml e adicione-a em todas as páginas necessárias com @ Html.Partial ("_ Breadcrumb")

_Breadcrumb.cshtml

<span>
    <a href="../@ViewData["controllerName"]">
        @ViewData["controllerName"]
    </a> > @ViewData["actionName"]
</span>
Kurkula
fonte
(1): Essa ainda é uma das formas mais comuns no MVC5? (2) De onde você tira sua filterContextvariável de dentro GetDefaults()?
chriszo111
1

Você pode obter o nome do controlador ou o nome da ação a partir da ação como qualquer variável. Eles são apenas especiais (controlador e ação) e já definidos, para que você não precise fazer nada de especial para obtê-los, exceto dizer que precisa deles.

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

Ou você pode incluir ação de controlador em seus modelos para obter dois deles e seus dados 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
fonte
1

Isso parece funcionar muito bem para mim (até agora), também funciona se você estiver usando o roteamento 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
fonte
1

Para remover a necessidade de ToString()uso de chamadas

string actionName = ControllerContext.RouteData.GetRequiredString("action");
string controllerName = ControllerContext.RouteData.GetRequiredString("controller");
Vadim Ovchinnikov
fonte
1

Use as linhas especificadas no OnActionExecuting for Action e no nome do Controller.

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

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

Bilal Raj
fonte
-8

Por que não ter algo mais simples?

Basta ligar Request.Path, ele retornará uma String Separada pelo "/"

e então você pode usar .Split('/')[1]para obter o nome do controlador.

insira a descrição da imagem aqui

adie wong
fonte
1
-1: com seu código, aplicativos de nível inferior são simplesmente ignorados (por exemplo http://www.example.com/sites/site1/controllerA/actionB/:). O MVC fornece várias APIs para roteamento, então por que você precisa analisar (novamente) URLs ?.
T-moty #
Por que reinventar a roda e, além disso, com uma má reinvenção? isso não funciona para todos os casos.
jstuardo
apartes de subpastas, o verdadeiro problema é que você pode personalizar suas rotas para que eles não serão semprecontroller/action
drzaus