Как я могу вернуть текущее действие в виде ASP.NET MVC?

291

Я хотел установить класс CSS на моей главной странице, который зависит от текущего контроллера и действия. Я могу добраться до текущего контроллера через ViewContext.Controller.GetType().Name, но как мне получить текущее действие (например Index, Showи т. Д.)?

Buggs
источник

Ответы:

83

Используйте ViewContextи посмотрите на RouteDataколлекцию, чтобы извлечь элементы контроллера и действия. Но я думаю, что установка некоторой переменной данных, которая указывает контекст приложения (например, «режим редактирования» или «ошибка»), а не контроллер / действие, уменьшает связь между вашими представлениями и контроллерами.

tvanfosson
источник
Вы можете получить данные в контроллере и передать их для просмотра с помощью DTO. stackoverflow.com/a/31749391/4293929
MstfAsan
5
это не должно быть принятым ответом, вместо этого посмотрите ответ с наибольшим количеством голосов.
Хакан Фистик,
1
@HakamFostok Я все еще думаю, что совет по добавлению семантической информации в модель во всех случаях является лучшим методом, чем полагаться на данные маршрута (контроллер, действие) в вашем представлении, даже если другой ответ предоставляет более подробную информацию о том, как получить эти данные.
tvanfosson
467

В RC вы также можете извлечь данные маршрута, например, имя метода действия, например:

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

Обновление для MVC 3

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

Обновление для MVC 4

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

Обновление для MVC 4.5

ViewContext.RouteData.Values["action"]
ViewContext.RouteData.Values["controller"]
ViewContext.RouteData.Values["id"]
Кристиан Далагер
источник
20
Я знаю, что это предшествует V2, но теперь это ViewContext.Controller.ValueProvider.GetValue("action").RawValue+ вариации
Крис S
7
Этот синтаксис работает в V4: (строка) ViewContext.RouteData.Values ​​["action"];
Кипрейни
2
Это решение не работает для меня (MVC4 + .NET Framework 4.5.1). Для меня это работает ответ Вячеслава Смитюха: ViewContext.RouteData.Values ​​["action"], ViewContext.RouteData.Values ​​["controller"], ViewContext.RouteData.Values ​​["id"],
Томас Кубес
@kiprainey В V3.5 тоже: msdn.microsoft.com/en-us/library/…
Плутон,
2
Попробуйте: (строка) HttpContext.Request.RequestContext.RouteData.Values ​​["action"];
Мартин Доусон
60

Чтобы получить текущий идентификатор в представлении:

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

Чтобы получить текущий контроллер:

ViewContext.RouteData.Values["controller"].ToString() 
tsquillario
источник
1
ViewContext.RouteData.Values ​​[<key>]. ToString () создает исключение, если значение не существует в RouteData
программное обеспечение Grizzly Peak,
@ShaneLarson Просто сравните с нулем или проверьте ViewContext.RouteData.Values.ContainsKey(<key>)сначала.
Плутон
40

Я знаю, что это более старый вопрос, но я видел его и подумал, что вам может быть интересна альтернативная версия, чем позволить вашему представлению обрабатывать данные, необходимые для его работы.

На мой взгляд, более простым способом было бы переопределить метод OnActionExecuting . Вам передается ActionExecutingContext, который содержит член ActionDescriptor, который вы можете использовать для получения искомой информации, который является ActionName, и вы также можете обратиться к ControllerDescriptor, который содержит 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.
}

Надеюсь это поможет. Если что-нибудь, по крайней мере, это покажет альтернативу для кого-либо еще, что приходит на ваш вопрос.

Дейл Раган
источник
хорошая рекомендация; помог мне в реализации контроллера / действия зондирования разумно. Спасибо!
effkay
Мне нужно было получить дескриптор действия, я не смог найти никакого другого решения, поэтому я просто сделал это здесь, а затем сунул то, что я хочу, в пакет просмотра.
Крис Марисик,
17

Я видел разные ответы и придумал помощника класса:

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

Так что в View (или master / layout) вы можете использовать его так (синтаксис 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>

Надеюсь, поможет.

Михаил Ващинский
источник
15

Вы можете получить эти данные из RouteData ViewContext

ViewContext.RouteData.Values["controller"]
ViewContext.RouteData.Values["action"]
Вячеслав Смитюх
источник
9

В MVC вы должны предоставлять View со всеми данными, а не позволять View собирать свои собственные данные, поэтому вы можете установить класс CSS в действии вашего контроллера.

ViewData["CssClass"] = "bold";

и выберите это значение из ваших ViewData в вашем View

terjetyl
источник
Это был бы мой предпочтительный метод, чтобы не допустить зависимости представлений от структуры контроллера, но это может быть сделано иначе.
tvanfosson
1
Не уверен, что я бы назвал его «CssClass», поскольку это, кажется, указывает на то, что логика отображения ползет в ваш контроллер.
tvanfosson
Согласен, я обычно делаю что-то вроде «Контекст», поэтому он не привязан к уровню представления и не прерывается, если вы переименуете представление.
RedFilter
6

Я голосую за это 2:

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

и

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

Вы можете получить как физическое имя текущего представления, так и действие, которое его вызвало. Это может быть полезно в частичных * .acmx страницах для определения хост-контейнера.


источник
2

Я использую ASP.NET MVC 4, и это то, что у меня сработало:

ControllerContext.Controller.ValueProvider.GetValue("controller").RawValue
ControllerContext.Controller.ValueProvider.GetValue("action").RawValue
kiewic
источник
0

Расширяя ответ Дейла Рэгана , его пример для повторного использования, создайте класс ApplicationController, который является производным от Controller, и, в свою очередь, все остальные контроллеры наследуются от этого класса ApplicationController, а не Controller.

Пример:

public class MyCustomApplicationController : Controller {}

public class HomeController : MyCustomApplicationController {}

В вашем новом ApplicationController создайте свойство с именем ExecutingAction с этой подписью:

protected ActionDescriptor ExecutingAction { get; set; }

А затем в методе OnActionExecuting (из ответа Дейла Рагана) просто назначьте ActionDescriptor этому свойству, и вы сможете получить к нему доступ, когда вам это понадобится в любом из ваших контроллеров.

string currentActionName = this.ExecutingAction.ActionName;
RunnerRick
источник
0

Переопределите эту функцию в вашем контроллере

protected override void HandleUnknownAction(string actionName) 
{  TempData["actionName"] = actionName;
   View("urViewName").ExecuteResult(this.ControllerContext);
}
Сантош Пандей
источник