如何在ASP.NET MVC视图中返回当前操作?

299

我想在母版页中设置一个 CSS 类,它取决于当前的控制器和操作。我可以通过 ViewContext.Controller.GetType().Name 访问当前的控制器,但是如何获取当前的操作(例如 IndexShow 等)?

11个回答

480
在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及其变体。 - Chris S
7
这个语法在 V4 版本中可行: (string)ViewContext.RouteData.Values["action"]; - kiprainey
2
这个解决方案对我不起作用(MVC4 + .NET Framework 4.5.1)。对我来说,Viacheslav Smityukh的答案有效:ViewContext.RouteData.Values["action"], ViewContext.RouteData.Values["controller"], ViewContext.RouteData.Values["id"], - Tomas Kubes
@kiprainey 在V3.5中也有:http://msdn.microsoft.com/zh-cn/library/system.web.mvc.viewcontext_members(v=vs.90).aspx#memberList2 - Pluto
你知道我怎么能获取Partial View的名称吗?我尝试了这个,但我总是得到一个View的Index,而我想要获取Partial View。 - user3281466
2
尝试:(字符串)HttpContext.Request.RequestContext.RouteData.Values [“action”]; - Martin Dawson

89

使用ViewContext并查看RouteData集合来提取控制器和操作元素。 但是我认为,设置一些指示应用程序上下文(例如,“editmode”或“error”)的数据变量而不是控制器/操作可以减少视图和控制器之间的耦合。


你可以在控制器中获取数据,并使用DTO将其传递到视图。https://dev59.com/XmMl5IYBdhLWcg3woYPa#31749391 - Mustafa ASAN
5
请参考最高投票的答案,这不应该被接受为正确答案。 - Hakan Fıstık
2
@HakamFostok,我仍然认为在所有情况下,向模型添加语义信息比依赖于路由数据(控制器、操作)在视图中更好的方法,即使其他答案提供了有关如何获取该数据的更多详细信息。 - tvanfosson

61

获取视图上当前 ID:

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

获取当前控制器:

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

1
如果在RouteData中不存在该值,则ViewContext.RouteData.Values[<key>].ToString()会抛出异常。 - Grizzly Peak Software
@ShaneLarson 首先只需与 null 进行比较或使用ViewContext.RouteData.Values.ContainsKey(<key>)进行检查。 - Pluto

41

我知道这是一个比较旧的问题,但我看到了它并认为您可能对另一种版本感兴趣,而不是让您的视图处理检索所需数据的工作。

在我看来,更简单的方法是覆盖OnActionExecuting方法。您将获得包含ActionDescriptor成员的ActionExecutingContext,您可以使用它来获取您正在寻找的信息,即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
获取操作描述符是我所需要的,我真的找不到其他解决方案,所以我只能在这里完成它,然后将我想要的内容放入视图包中。 - Chris Marisic

18

我看到了不同的答案并且写了一个类助手:

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

因此,在视图(或主/布局)中,您可以像这样使用它(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>
希望对你有所帮助。

16
您可以从ViewContext的RouteData中获取这些数据。
ViewContext.RouteData.Values["controller"]
ViewContext.RouteData.Values["action"]

10
在MVC中,你应该向View提供所有数据,而不是让View自己收集数据,因此你可以在Controller Action中设置CSS类。
ViewData["CssClass"] = "bold";

然后在您的视图中从ViewData中挑选出这个值。


这也是我首选的方法,可以避免视图依赖于控制器结构,但也可以用其他方法实现。 - tvanfosson
1
我不确定是否应该将之命名为“CssClass”,因为这似乎暗示着显示逻辑正在渗入您的控制器。 - tvanfosson
同意,我通常会使用“Context”这样的东西,这样它就不会与表示层绑定,并且如果您重命名视图,它也不会出错。 - D'Arcy Rittich

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

0

在您的控制器中覆盖此函数

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接