【问题标题】:Get controller and action name from within controller?从控制器中获取控制器和动作名称?
【发布时间】:2013-08-17 09:33:18
【问题描述】:

对于我们的 Web 应用程序,我需要根据视图保存获取和显示项目的顺序 - 或者更准确地说 - 生成视图的控制器和操作(当然还有用户 ID,但这不是重点在这里)。

我认为从控制器和操作自动创建此标识符会更安全、更容易,而不仅仅是在每个控制器操作中自己给出一个标识符(以便将其用于一些依赖于视图的 DB 输出排序)调用它的方法。

如何从控制器的操作方法中获取控制器的名称和操作?或者我需要为此反思吗?

【问题讨论】:

  • Reflection 会给你处理动作的方法名,但大概你更喜欢 Andrei 的代码返回的动作名。
  • 我基本上只需要为每个提供视图的操作提供一个明确的标识符,因此两种方式都可以完成工作。但你是对的,安德烈的回答肯定更优雅。
  • @citykid 除了大小写和类名的“控制器”后缀之外,是否存在其他方式不同的情况?
  • @John,ActionNameAttribute 允许 c# 方法具有任何操作名称:msdn.microsoft.com/en-us/library/…
  • @citykid 哦,好的。鉴于您可以在我收集的操作方法上使用 Route 属性指定路由,这是一种过时的功能?另外,是否也可以重命名控制器?

标签: c# asp.net-mvc controller action


【解决方案1】:
string actionName = this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();

【讨论】:

  • 在某些情况下,您可能希望在视图文件中包含控制器的名称,那么您可以使用 this.ViewContext.RouteData.Values["controller"].ToString();
  • 如果你要这样做(提供动作和控制器名称),为什么不直接分配它们???
  • @MetalPhoenix,你能澄清一下你在说什么用例吗? OP 不需要分配控制器或动作 - 他们只需要以一般方式了解当前正在处理的控制器和动作是什么。
  • 在第二次阅读时,我是否可能误解了这里的代码片段? ...Values["action"] 其中“action”是键而不是要替换的操作的名称(例如“'Pass123' without the quotes”类型的东西)?也就是说:还是会是 Values["action"] 而不是 Values["yourAction"]?
  • @MetalPhoenix,确切地说,“action”字面量是一个键,Values[“action”] 将输出“CurrentActionName”
【解决方案2】:

以下是一些用于获取该信息的扩展方法(它还包括 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;
    }
}

用法:

@Html.Controller();
@Html.Action();
@Html.Id();

【讨论】:

  • 最佳和完整的解决方案,谢谢 Jhon
  • 在 ASP.NET Core 中不起作用,因为 HttpContext.Current 不再存在
【解决方案3】:

可能有用。我需要控制器的 构造函数 中的操作,它出现在 MVC 生命周期的这一点上,this 尚未初始化,ControllerContext = null。我没有深入研究 MVC 生命周期并找到要覆盖的适当函数名称,而是在 RequestContext.RouteData 中找到了该操作。

但为了做到这一点,与构造函数中的任何HttpContext 相关使用一样,您必须指定完整的命名空间,因为this.HttpContext 还没有被初始化。幸运的是,System.Web.HttpContext.Current 似乎是静态的。

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

注意:可能不是访问 HttpContext 中所有属性的最受支持的方式,但对于 RequestContext 和 Session,它似乎在我的应用程序中工作正常。

【讨论】:

  • 我只是尝试覆盖 MVC 5 中的 ControllerFactory 方法以尝试在构造后执行一个通用方法,因为我需要获取 HttpContext 和 Session 而它在构造函数中不起作用。即使在构造完成之后,也没有设置工厂可以对其进行任何操作的值,因此必须在控制器工厂完成操作后设置它们。
【解决方案4】:
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();
    }
}

【讨论】:

    【解决方案5】:
     @this.ViewContext.RouteData.Values["controller"].ToString();
    

    【讨论】:

      【解决方案6】:

      这是我目前所拥有的:

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

      【讨论】:

        【解决方案7】:

        这是获得名字的最简单和最实用的答案:

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

        或者

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

        上面的代码用 asp.net mvc 5 测试。

        【讨论】:

          【解决方案8】:

          这对我来说似乎很好用(到目前为止),如果你使用属性路由也可以。

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

          【讨论】:

            【解决方案9】:

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

            实现你的控制器到Basecontroller

            添加部分视图 _Breadcrumb.cshtml 并将其添加到所有需要的页面中 @Html.Partial("_Breadcrumb")

            _Breadcrumb.cshtml

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

            【讨论】:

            • (1):这仍然是 MVC5 中最常见的方式之一吗? (2) 你从GetDefaults() 中从哪里得到你的filterContext 变量?
            【解决方案10】:

            您可以像任何变量一样从动作中获取控制器名称或动作名称。它们只是特殊的(控制器和操作),并且已经定义,因此您无需执行任何特殊操作即可获取它们,只需告诉您需要它们。

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

            或者,您可以在模型中包含控制器、操作以获取其中两个和您的自定义数据。

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

            【讨论】:

              【解决方案11】:

              要消除对ToString() 调用的需要

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

              【讨论】:

                【解决方案12】:

                试试这个代码

                将此覆盖方法添加到控制器

                protected override void OnActionExecuting(ActionExecutingContext actionExecutingContext)
                {
                   var actionName = actionExecutingContext.ActionDescriptor.ActionName;
                   var controllerName = actionExecutingContext.ActionDescriptor.ControllerDescriptor.ControllerName;
                   base.OnActionExecuting(actionExecutingContext);
                }
                

                【讨论】:

                  【解决方案13】:

                  为什么不来点更简单的?

                  只要调用Request.Path,它会返回一个用“/”分隔的字符串

                  然后您可以使用.Split('/')[1] 获取控制器名称。

                  【讨论】:

                  • -1:使用您的代码,子级应用程序将被简单地忽略(例如:http://www.example.com/sites/site1/controllerA/actionB/)。 MVC 提供了一堆用于路由的 API,那么为什么需要(再次)解析 URL?。
                  • 为什么要重新发明轮子,而且重新发明很糟糕?这不适用于所有情况。
                  • 除了子文件夹,真正的问题是你可以自定义你的路线,所以它们不会总是controller/action
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-04-27
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-02-29
                  • 2013-07-24
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多