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!


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();

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();

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.


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

Oto, co mam do tej pory:

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

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.


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>

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

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

1

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

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

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 ();


-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


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.