Ottieni il controller e il nome dell'azione dal controller?


173

Per la nostra applicazione web ho bisogno di salvare l'ordine degli elementi recuperati e visualizzati a seconda della vista - o per essere precisi - il controller e l'azione che hanno generato la vista (e l'id utente ovviamente, ma non è questo il punto qui).

Invece di fornire semplicemente un identificatore in ogni azione del controller (al fine di usarlo per un ordinamento delle uscite DB dipendente dalla vista), ho pensato che sarebbe stato più sicuro e più semplice creare questo identificatore automaticamente dal controller e dal metodo di azione che ottiene chiamato da.

Come posso ottenere il nome del controller e l'azione dal metodo action in un controller? O ho bisogno di riflessione per quello? Immagino sia abbastanza facile, grazie in anticipo!


1
Reflection ti darebbe il nome del metodo che gestisce l'azione, ma presumibilmente preferisci il nome dell'azione restituito dal codice di Andrei.
citykid,

Fondamentalmente ho solo bisogno di un identificatore inequivocabile per ogni azione che offra una visione, quindi entrambi i modi farebbero il lavoro. Ma hai ragione, la risposta di Andrei è decisamente più elegante.
Alex

@citykid Ci sono casi in cui differiscono in modi diversi dal caso e dal suffisso "Controller" per i nomi delle classi?
Giovanni

@ John, ActionNameAttribute permette ac # metodo per avere qualsiasi nome dell'azione: msdn.microsoft.com/en-us/library/...
citykid

@citykid Oh, ok. È una specie di caratteristica obsoleta dato che puoi specificare le rotte con un Routeattributo sul metodo di azione che raccolgo? Inoltre, è anche possibile rinominare i controller?
Giovanni

Risposte:


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

13
In alcuni casi in cui potresti voler avere il nome del controller nel file Visualizza, puoi semplicemente usare this.ViewContext.RouteData.Values ​​["controller"]. ToString ();
Amogh Natu,

Se hai intenzione di farlo (fornisci il nome dell'azione e del controller), perché non assegnarli direttamente ???
MetalPhoenix,

1
@MetalPhoenix, puoi chiarire un po 'di quale caso d'uso stai parlando? L'OP non ha bisogno di assegnare il controller o l'azione: devono solo capire, in modo generico, quali sono il controller e l'azione attualmente in fase di elaborazione.
Andrei,

1
In una seconda lettura, è possibile che abbia frainteso lo snippit di codice qui? ... Valori ["azione"] dove "azione" è una chiave e non il nome dell'azione da sostituire (come "'Pass123' senza virgolette" tipo di cosa)? Vale a dire: sarebbe ancora Values ​​["action"] invece di Values ​​["yourAction"]?
MetalPhoenix

@MetalPhoenix, esattamente, "azione" letterale è una chiave, e Valori ["azione"] produrrà "CurrentActionName"
Andrei

62

Ecco alcuni metodi di estensione per ottenere tali informazioni (include anche l'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
Soluzione migliore e completa, grazie Jhon
Umar Abbas,

24

Potrebbe essere utile. Avevo bisogno dell'azione nel costruttore del controller, e appare a questo punto del ciclo di vita di MVC, thisnon è stato inizializzato e ControllerContext = null. Invece di approfondire il ciclo di vita di MVC e trovare il nome della funzione appropriata da sovrascrivere, ho appena trovato l'azione nelRequestContext.RouteData .

Ma per fare ciò, come per qualsiasi HttpContextuso correlato nel costruttore, è necessario specificare lo spazio dei nomi completo, perché this.HttpContextanche questo non è stato inizializzato. Fortunatamente, sembra System.Web.HttpContext.Currentstatico.

// 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: probabilmente non è il modo più supportato per accedere a tutte le proprietà in HttpContext, ma per RequestContext e Session sembra funzionare bene nella mia applicazione.


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

Questo è quello che ho finora:

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

3

Ecco la risposta più semplice e pratica per ottenere un nome:

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

O

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

Codice sopra test con asp.net mvc 5.


2

Aggiungi questo al controller di base nel metodo 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;
    }

Implementa i tuoi controller su Basecontroller

Aggiungi una vista parziale _Breadcrumb.cshtml e aggiungila in tutte le pagine richieste con @ Html.Partial ("_ Breadcrumb")

_Breadcrumb.cshtml

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

(1): è ancora uno dei modi più comuni all'interno di MVC5? (2) Da dove prendi la tua filterContextvariabile dall'interno GetDefaults()?
chriszo111,

1

È possibile ottenere il nome del controller o il nome dell'azione dall'azione come qualsiasi variabile. Sono solo speciali (controller e azione) e sono già definiti, quindi non è necessario fare nulla di speciale per ottenerli se non per dirti che ne hai bisogno.

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

Oppure puoi includere controller, azione nei tuoi modelli per ottenerne due e i tuoi dati personalizzati.

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

Questo sembra funzionare bene per me (finora), funziona anche se si utilizza il routing degli attributi.

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

Per rimuovere la necessità di ToString()utilizzare la chiamata

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

1

Utilizzare le righe fornite in OnActionExecuting per azione e nome del controller.

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

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


-8

Perché non avere qualcosa di più semplice?

Basta chiamare Request.Path, restituirà una stringa separata dal "/"

e quindi è possibile utilizzare .Split('/')[1]per ottenere il nome del controller.

inserisci qui la descrizione dell'immagine


1
-1: con il tuo codice, le applicazioni di livello inferiore vengono semplicemente ignorate (ad es http://www.example.com/sites/site1/controllerA/actionB/.:). MVC fornisce un sacco di API per il routing, quindi perché è necessario analizzare (di nuovo) gli URL ?.
T-moty,

Perché reinventare la ruota e, inoltre, con una scarsa reinvenzione? questo non funziona in tutti i casi.
jstuardo,

a parte le sottocartelle, il vero problema è che puoi personalizzare i tuoi percorsi in modo che non siano semprecontroller/action
drzaus,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.