Czy uzyskać nazwę kontrolera i akcji z poziomu kontrolera?

173

W naszej aplikacji internetowej muszę zapisać kolejność pobieranych i wyświetlanych elementów w zależności od widoku - a dokładniej - kontrolera i akcji, która wygenerowała widok (i oczywiście identyfikator użytkownika, ale nie o to tutaj chodzi).

Zamiast po prostu podawać identyfikator w każdej akcji kontrolera (aby użyć go do sortowania danych wyjściowych DB zależnych od widoku), pomyślałem, że bezpieczniej i łatwiej byłoby utworzyć ten identyfikator automatycznie na podstawie kontrolera i metody akcji, którą otrzymuje dzwonił z.

Jak mogę uzyskać nazwę kontrolera i akcję z metody akcji w kontrolerze? A może potrzebuję do tego refleksji? Myślę, że to całkiem proste, z góry dzięki!

Alex
źródło
1
Odbicie dałoby ci nazwę metody, która obsługuje akcję, ale prawdopodobnie wolisz nazwę akcji zwracaną przez kod Andrieja.
citykid
Po prostu potrzebuję jednoznacznego identyfikatora dla każdego działania, które dostarcza widok, więc oba sposoby wystarczą. Ale masz rację, odpowiedź Andrieja jest zdecydowanie bardziej elegancka.
Alex
@citykid Czy istnieją przypadki, w których sposoby różnią się od siebie innymi niż wielkość liter i przyrostek „Kontroler” dla nazw klas?
Jan
@John, ActionNameAttribute pozwala metodzie ac # na posiadanie dowolnej nazwy akcji: msdn.microsoft.com/en-us/library/…
citykid
@citykid Oh, ok. To trochę przestarzała funkcja, biorąc pod uwagę, że możesz określić trasy za pomocą Routeatrybutu w metodzie akcji, którą zbieram? Czy jest również możliwa zmiana nazw kontrolerów?
Jan

Odpowiedzi:

345
string actionName = this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();
Andrei
źródło
13
W niektórych przypadkach, gdy chciałbyś mieć nazwę kontrolera w pliku View, możesz po prostu użyć this.ViewContext.RouteData.Values ​​["controller"]. ToString ();
Amogh Natu
Jeśli masz zamiar to zrobić (podaj akcję i nazwę kontrolera), dlaczego nie przypisać ich bezpośrednio ???
MetalPhoenix
1
@MetalPhoenix, czy możesz trochę wyjaśnić, o jakim przypadku użycia mówisz? OP nie musi przypisywać kontrolera ani akcji - wystarczy, że zrozumieją, w ogólny sposób, jaki jest administrator i jaka akcja jest obecnie przetwarzana.
Andrei
1
Po drugim czytaniu, czy to możliwe, że źle zrozumiałem fragment kodu? ... Wartości [„akcja”], gdzie „akcja” jest kluczem, a nie nazwą akcji, która ma zostać podstawiona (np. „Pass123” bez cudzysłowów)? To znaczy: czy nadal byłyby wartościami [„akcja”] zamiast wartości [„twoja akcja”]?
MetalPhoenix
@MetalPhoenix, dokładnie, literał „action” jest kluczem, a wartości [„action”] zwróci „CurrentActionName”
Andrei
62

Oto kilka metod rozszerzających służących do uzyskiwania tych informacji (obejmuje również identyfikator):

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

Stosowanie:

@Html.Controller();
@Html.Action();
@Html.Id();
John Bubriski
źródło
1
Najlepsze i kompletne rozwiązanie, dzięki Jhon
Umar Abbas
24

Może się przydać. Potrzebowałem akcji w konstruktorze kontrolera i pojawia się ona w tym momencie cyklu życia MVC, thisnie została zainicjowana i ControllerContext = null. Zamiast zagłębiać się w cykl życia MVC i znaleźć odpowiednią nazwę funkcji do zastąpienia, po prostu znalazłem akcję w RequestContext.RouteData.

Ale aby to zrobić, tak jak w przypadku innych HttpContextpowiązanych zastosowań w konstruktorze, musisz określić pełną przestrzeń nazw, ponieważ this.HttpContextrównież nie została zainicjowana. Na szczęście wydaje się, że System.Web.HttpContext.Currentjest statyczny.

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

UWAGA: prawdopodobnie nie jest to najbardziej obsługiwany sposób uzyskiwania dostępu do wszystkich właściwości w HttpContext, ale w przypadku RequestContext i Session wydaje się, że działa dobrze w mojej aplikacji.

sonjz
źródło
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
źródło
5
 @this.ViewContext.RouteData.Values["controller"].ToString();
Hossein Hajizadeh
źródło
4

Oto, co mam do tej pory:

var actionName = filterContext.ActionDescriptor.ActionName;
var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
user3563149
źródło
3

Oto najprostsza i najbardziej praktyczna odpowiedź na pytanie:

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

Lub

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

Kod powyżej testów z asp.net mvc 5.

Matheus Miranda
źródło
2

Dodaj to do kontrolera podstawowego w metodzie 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;
    }

Zaimplementuj kontrolery do Basecontroller

Dodaj częściowy widok _Breadcrumb.cshtml i dodaj go na wszystkich wymaganych stronach z @ Html.Partial ("_ Breadcrumb")

_Breadcrumb.cshtml

<span>
    <a href="../@ViewData["controllerName"]">
        @ViewData["controllerName"]
    </a> > @ViewData["actionName"]
</span>
Kurkula
źródło
(1): Czy jest to nadal jeden z najczęstszych sposobów w MVC5? (2) Skąd bierzesz filterContextzmienną od wewnątrz GetDefaults()?
chriszo111
1

Możesz uzyskać nazwę kontrolera lub nazwę akcji z akcji, jak każda zmienna. Są po prostu specjalne (kontroler i akcja) i już zdefiniowane, więc nie musisz robić nic specjalnego, aby je zdobyć, z wyjątkiem mówienia, że ​​ich potrzebujesz.

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

Lub możesz dołączyć kontroler, akcję do swoich modeli, aby uzyskać dwa z nich i własne dane.

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
źródło
1

Wydaje mi się, że działa to dobrze (na razie), działa również, jeśli używasz routingu atrybutów.

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
źródło
1

Aby usunąć potrzebę ToString()korzystania z połączeń

string actionName = ControllerContext.RouteData.GetRequiredString("action");
string controllerName = ControllerContext.RouteData.GetRequiredString("controller");
Vadim Ovchinnikov
źródło
1

Użyj podanych wierszy w OnActionExecuting dla nazwy akcji i kontrolera.

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

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

Bilal Raj
źródło
-8

Dlaczego nie mieć czegoś prostszego?

Po prostu zadzwoń Request.Path, zwróci ciąg oddzielony znakiem „/”

a następnie możesz użyć, .Split('/')[1]aby uzyskać nazwę kontrolera.

wprowadź opis obrazu tutaj

adie wong
źródło
1
-1: w Twoim kodzie aplikacje podpoziomowe są po prostu ignorowane (np http://www.example.com/sites/site1/controllerA/actionB/.:). MVC zapewnia kilka interfejsów API do routingu, więc dlaczego musisz analizować (ponownie) adresy URL ?.
T-moty
Po co wymyślać koło na nowo, a co więcej, ze słabym wymyśleniem? to nie działa we wszystkich przypadkach.
jstuardo,
poza podfolderami, prawdziwym problemem jest to, że możesz dostosować swoje trasy, aby nie zawsze byłycontroller/action
drzaus