Como posso retornar a ação atual em um modo de exibição do ASP.NET MVC?

291

Eu queria definir uma classe CSS na minha página mestre, que depende do controlador e da ação atuais. Posso acessar o controlador atual via ViewContext.Controller.GetType().Name, mas como faço para obter a ação atual (por exemplo Index, Showetc.)?

buggs
fonte

Respostas:

83

Use ViewContexte veja a RouteDatacoleção para extrair os elementos do controlador e da ação. Mas acho que definir algumas variáveis ​​de dados que indicam o contexto do aplicativo (por exemplo, "modo de edição" ou "erro") em vez de controlador / ação reduz o acoplamento entre suas visualizações e controladores.

tvanfosson
fonte
você pode obter dados no controlador e passá-los para visualização com o DTO. stackoverflow.com/a/31749391/4293929
MstfAsan
5
essa NÃO deve ser a resposta aceita; veja a resposta mais votada.
Hakan Fıstık
1
@HakamFostok Ainda acho que o conselho para adicionar informações semânticas ao modelo é um método melhor em todos os casos do que confiar nos dados da rota (controlador, ação) na sua opinião, mesmo que a outra resposta forneça mais detalhes sobre como obter esses dados.
tvanfosson
467

No RC, você também pode extrair dados da rota como o nome do método de ação como este

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

Atualização para MVC 3

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

Atualização para MVC 4

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

Atualização para MVC 4.5

ViewContext.RouteData.Values["action"]
ViewContext.RouteData.Values["controller"]
ViewContext.RouteData.Values["id"]
Christian Dalager
fonte
20
Eu sei que isso datas pré-V2, mas é agora ViewContext.Controller.ValueProvider.GetValue("action").RawValue+ variações
Chris S
7
Essa sintaxe funciona na V4: (string) ViewContext.RouteData.Values ​​["action"];
28813 kiprainey
2
Esta solução não funciona para mim (MVC4 + .NET Framework 4.5.1). Para mim, funciona a resposta de Viacheslav Smityukh: ViewContext.RouteData.Values ​​["action"], ViewContext.RouteData.Values ​​["controller"], ViewContext.RouteData.Values ​​["id"],
Tomas Kubes
@kiprainey Na V3.5 também: msdn.microsoft.com/en-us/library/…
Plutão
2
Tente: (string) HttpContext.Request.RequestContext.RouteData.Values ​​["action"];
Martin Dawson
60

Para obter o ID atual em uma Visualização:

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

Para obter o controlador atual:

ViewContext.RouteData.Values["controller"].ToString() 
tsquillario
fonte
1
. ViewContext.RouteData.Values [<key>] ToString () lança uma exceção se o valor não existe no RouteData
Grizzly Peak Software
@ShaneLarson Basta comparar com nulo ou verificar com ViewContext.RouteData.Values.ContainsKey(<key>)primeiro.
Plutão
40

Sei que essa é uma pergunta mais antiga, mas eu a vi e pensei que você poderia estar interessado em uma versão alternativa do que permitir que sua visualização lide com a recuperação dos dados necessários para seu trabalho.

Uma maneira mais fácil, na minha opinião, seria substituir o método OnActionExecuting . Você recebe o ActionExecutingContext que contém o membro ActionDescriptor que você pode usar para obter as informações que procura, que é o ActionName e também é possível acessar o ControllerDescriptor e o 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 isto ajude. Se alguma coisa, pelo menos, mostrará uma alternativa para qualquer outra pessoa que vier com sua pergunta.

Dale Ragan
fonte
boa recomendação; me ajudou a implementar o controlador / ação de detecção inteligente. Obrigado!
214 efkay #
Obter o desrciptor de ação é o que eu precisava, não consegui encontrar outra solução, então apenas o faço aqui e depois enfio o que quero na sacola.
22612 Chris Marisic
17

Vi respostas diferentes e criei um ajudante de classe:

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

Portanto, no modo de exibição (ou mestre / layout), você pode usá-lo da seguinte maneira (sintaxe do 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 que ajude.

Michael Vashchinsky
fonte
15

Você pode obter esses dados do RouteData de um ViewContext

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

No MVC, você deve fornecer ao View todos os dados, não permitir que o View colete seus próprios dados, para que você possa definir a classe CSS na ação do seu controlador.

ViewData["CssClass"] = "bold";

e escolha esse valor no seu ViewData no seu View

terjetil
fonte
Esse seria o meu método preferido também para impedir que as visualizações dependessem da estrutura do controlador, mas pode ser feito de outra forma.
tvanfosson 12/12/08
1
Não tenho certeza se eu o chamaria "CssClass", pois isso parece indicar que a lógica de exibição está entrando no seu controlador.
tvanfosson 12/12/08
Concordo, eu costumo fazer algo como "Contexto", para que ele não esteja vinculado à camada de apresentação e não quebre se você renomear a exibição.
RedFilter
6

Eu voto para este 2:

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

e

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

Você pode recuperar o nome físico da visualização atual e a ação que a acionou. Pode ser útil em páginas * .acmx parciais para determinar o contêiner do host.


fonte
2

Estou usando o ASP.NET MVC 4, e foi isso que funcionou para mim:

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

Estendendo a resposta de Dale Ragan , seu exemplo para reutilização, crie uma classe ApplicationController que deriva do Controller e, por sua vez, todos os outros controladores derivam dessa classe ApplicationController em vez de Controller.

Exemplo:

public class MyCustomApplicationController : Controller {}

public class HomeController : MyCustomApplicationController {}

No seu novo ApplicationController, crie uma propriedade chamada ExecutingAction com esta assinatura:

protected ActionDescriptor ExecutingAction { get; set; }

E então, no método OnActionExecuting (da resposta de Dale Ragan), simplesmente atribua o ActionDescriptor a essa propriedade e você poderá acessá-lo sempre que precisar em qualquer um dos seus controladores.

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

Substitua esta função no seu controlador

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