【问题标题】:How do I get Route name from RouteData?如何从 RouteData 获取路线名称?
【发布时间】:2011-04-26 15:53:40
【问题描述】:

我在 Global.asax 中定义了几条路线;

当我在一个页面上时,我需要弄清楚当前路由的路由名称是什么,因为路由名称驱动着我的站点菜单。

如何做到这一点?

【问题讨论】:

    标签: asp.net routing webforms url-routing


    【解决方案1】:

    如果您正在处理需要检查的重要路线的一小部分(一两个特殊情况),您可以这样做:

    if (routeData.Route == RouteTable.Routes["gallery-route"])
    {
       // current route is 'gallery-route'
    }
    

    需要路由名称的一个常见原因是出于调试目的。下面是一种快速而肮脏的方法 - 但您需要将每个路由名称添加到名称数组中。调试应该没问题 - 特别是如果代码在生产期间没有运行。

    // quick and dirty way to get route name
    public string GetRouteName(RouteData routeData) 
    {
        foreach (string name in new [] { "gallery-route", 
                                         "products-route", 
                                         "affiliate-route", 
                                         "default" }) 
        {
            if (routeData.Route == RouteTable.Routes[name])
            {
                return name;
            }
        }
        return "UNKNOWN-ROUTE";   // or throw exception
    }
    

    除此之外,您应该花费@haacked 解决方案所需的(最少)时间。

    【讨论】:

    • 感谢您的提示。您的第一个想法对我来说非常有效,因为我只需要在文章页面中检查它们是通过 title 路线还是 rowid 路线来的。加油!
    【解决方案2】:

    您可以添加每个路由参数,而这些参数不必在您的 Url 中: 您可以将您的路线名称作为参数放在Global.asax中:

     routes.MapPageRoute("Page",
                    "Page-{ID}",
                   "~/Item_show.aspx", false, new RouteValueDictionary{ { "RouteName" , "Page" }});
    

    并在您的页面中访问它:

    if (RouteData.Values["RouteName"] != null)
               {
                   if (RouteData.Values["RouteName"].ToString() == "Page")
                   {
                       Response.Write(RouteData.Values["RouteName"]);
    
                   }  
    
               }
    

    最好的方法并不难。

    【讨论】:

      【解决方案3】:

      对于 C#,您可以像这样声明您的路线:

              routeCollection.MapPageRoute("RouteForProduct", "Product/{ProductName}", "~/IRShop.aspx", false, new RouteValueDictionary { { "Section", "product" } });
              routeCollection.MapPageRoute("RouteForProductList", "ProductList/{CatName}", "~/IRShop.aspx", false, new RouteValueDictionary { { "Section", "productlist" } });
              routeCollection.MapPageRoute("RouteForContentList", "Content/{PageName}", "~/IRShop.aspx", false, new RouteValueDictionary { { "Section", "content" } });
      

      然后在您需要路线的方法中,您可以调用以下内容:

      var x = Page.RouteData.Values["Section"].ToString();
      

      您将在 global.asax 中设置一个字符串,然后根据需要使用。

      【讨论】:

        【解决方案4】:

        FWIW,由于 @Simon_Weaver 显示的扩展和示例是基于 MVC 的,并且帖子标记为 WebForms,我想我会分享我基于 WebForms 的扩展方法:

            public static void MapPageRouteWithName(this RouteCollection routes, string routeName, string routeUrl, string physicalFile, bool checkPhysicalUrlAccess = true,
                    RouteValueDictionary defaults = default(RouteValueDictionary), RouteValueDictionary constraints = default(RouteValueDictionary), RouteValueDictionary dataTokens = default(RouteValueDictionary))
            {
                if (dataTokens == null)
                    dataTokens = new RouteValueDictionary();
        
                dataTokens.Add("route-name", routeName);
                routes.MapPageRoute(routeName, routeUrl, physicalFile, checkPhysicalUrlAccess, defaults, constraints, dataTokens);
            }
        
            public static string GetRouteName(this RouteData routeData) 
            {
                if (routeData.DataTokens["route-name"] != null)
                    return routeData.DataTokens["route-name"].ToString();
                else return String.Empty;
            }
        

        所以现在在 Global.asax.cs 中注册路由时,不要像 routes.MapPageRoute(...) 一样 - 而是使用扩展方法并执行 routes.MapPageRouteWithName(...)

        然后当你想检查你在哪条路线上时,只需执行 Page.RouteData.GetRouteName()

        就是这样。没有反射,对“路由名称”的唯一硬编码引用在两个扩展方法中(如果你真的想的话,可以用 const 替换)。

        【讨论】:

        • +1,感谢您为我保存了 MVC-->WebForms 翻译练习。
        【解决方案5】:

        我实现的一个简单方法是为 .MapPageRoute 方法的“默认”参数提供一个命名键。使用常量作为默认值,您可以像往常一样将其从 Page.RouteData.Values 集合中拉出。

        示例(vb.net)

        routes.MapPageRoute("league-division-stats", "{league}/{division}/stats", "~/routes/league-division-stats.aspx", False, New RouteValueDictionary(New With {.section = "stats"}))
        

        Page.RouteData.Values("section") 给我“统计数据”

        【讨论】:

          【解决方案6】:

          RouteCollection 维护着一个命名路由的私有字典。

          路线名称可以通过

          1. 使用反射检索私有字段的值并
          2. 在字典中查询其值为路由的项。

          下面的扩展方法遵循这个过程:

          public static string Name(this RouteBase original)
          {
              var routes = System.Web.Routing.RouteTable.Routes;
          
              if (routes.Contains(original))
              {
                  var namedMapField = routes.GetType().GetField("_namedMap", BindingFlags.NonPublic | BindingFlags.Instance);
                  var namedMap = namedMapField.GetValue(routes) as Dictionary<string, RouteBase>;
          
                  var query = 
                      from pair in namedMap 
                      where pair.Value == original 
                      select pair.Key;
          
                  return query.Single();
              }
          
              return string.Empty;
          }
          

          【讨论】:

            【解决方案7】:

            我会投票赞成 Simon_Weaver 的回答,但不幸的是我刚刚加入,没有声望点。

            添加到他的答案,因为这正是我正在寻找的,这就是我这样做的方式:

            我有一个公共枚举“PageRouteTable”:

            public enum PageRouteTable
            {
                // -- User Area
                UserArea_Locations,
                UserArea_Default,
                UserArea_PasswordReset,
                UserArea_Settings,
                .
                .
                .
            }
            

            我在构建路线时使用这个枚举:

            /* -- User Area Routes -- */
            routes.MapPageRoute(PageRouteTable.UserArea_Default.ToString(), "home", "~/UserArea/Default.aspx");
            

            然后我创建了一个页面扩展方法:

            public static PageRouteTable? CurrentRoute(this Page p)
            {
                string[] pageRoutes = Enum.GetNames(typeof (PageRouteTable));
                foreach (string pageRoute in pageRoutes)
                {
                    if (p.RouteData.Route == RouteTable.Routes[pageRoute])
                    {
                        return (PageRouteTable)Enum.Parse(typeof (PageRouteTable), pageRoute);
                    }
                }
                return null;
            }
            

            现在在我的页面中,我可以简单地使用一个开关来操作它:

            PageRouteTable? currentRoute = this.CurrentRoute();
            if (currentRoute.HasValue) {
                switch(currentRoute.Value) {
                    case PageRouteTable.UserArea_Default:
                        // Act accordingly
                        break;
                    .
                    .
                    .
                }
            }
            

            我也有明确定义的变量的好处,不必担心针对字符串进行编码。这为我省去了很多维护方面的麻烦。

            -- 快乐的编码。

            【讨论】:

              【解决方案8】:

              这是@haacked 建议的一个实现——还有一个简单的“剃刀”表来显示路线数据。

              注意:您可能没有意识到所有标准的“MapRoute”方法实际上都是扩展方法。因此,我们不能使用相同的名称。我刚刚将其称为“MapRoute2”,因为现在我能想到的就这些了。

              您必须将所有对 MapRoute 的调用替换为对 MapRoute2 的调用,不要忘记所有 AreaRegistration 文件以及 global.asax.cs

              扩展方法:

              public static class RouteNameExtensions
              {
                  // RouteCollection
                  public static Route MapRoute2(this RouteCollection routes, string name, string url)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url));
                  }
              
                  public static Route MapRoute2(this RouteCollection routes, string name, string url, object defaults)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url, defaults));
                  }
              
                  public static Route MapRoute2(this RouteCollection routes, string name, string url, string[] namespaces)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url, namespaces));
                  }
              
                  public static Route MapRoute2(this RouteCollection routes, string name, string url, object defaults, object constraints)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url, defaults, constraints));
                  }
              
                  public static Route MapRoute2(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url, defaults, namespaces));
                  }
              
                  public static Route MapRoute2(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url, defaults, constraints, namespaces));
                  }
              
                  // AreaRegistrationContext
                  public static Route MapRoute2(this AreaRegistrationContext routes, string name, string url)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url));
                  }
              
                  public static Route MapRoute2(this AreaRegistrationContext routes, string name, string url, object defaults)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url, defaults));
                  }
              
                  public static Route MapRoute2(this AreaRegistrationContext routes, string name, string url, string[] namespaces)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url, namespaces));
                  }
              
                  public static Route MapRoute2(this AreaRegistrationContext routes, string name, string url, object defaults, object constraints)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url, defaults, constraints));
                  }
              
                  public static Route MapRoute2(this AreaRegistrationContext routes, string name, string url, object defaults, string[] namespaces)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url, defaults, namespaces));
                  }
              
                  public static Route MapRoute2(this AreaRegistrationContext routes, string name, string url, object defaults, object constraints, string[] namespaces)
                  {
                      return AddRouteNameDataToken(name, routes.MapRoute(name, url, defaults, constraints, namespaces));
                  }
              
                  private static Route AddRouteNameDataToken(string name, Route route)
                  {
                      route.DataTokens["route-name"] = name;
                      return route;
                  }
              }
              

              这是我用来显示路由信息的简单 razor .cshtml 文件:

              <table class="basic-table">
                  <tr>
                      <th>Route Key</th>
                      <th>Value</th>
                  </tr>
              
                  <tr>
                      <td><strong>Route name</strong></td>
                      <td>@ViewContext.RouteData.DataTokens["route-name"]</td>
                  </tr>
              
                  @foreach (var route in ViewContext.RouteData.Values)
                  {
                      <tr>
                          <td>- @route.Key</td>
                          <td>@(route.Value ?? "<null>")</td>
                      </tr>
                  }
                  @foreach (var route in ViewContext.RouteData.DataTokens.Where(x=>x.Key != "route-name"))
                  {
                      <tr>
                          <td><strong>@route.Key</strong></td>
                          <td>@(route.Value ?? "<null>")</td>
                      </tr>
                  }
              
              </table>
              

              【讨论】:

              • 这就是我在 10 月份 Haacked 建议时实现它的方式 :) 无论如何感谢您的提示
              • 我想这是唯一的方法 ;-) 编写所有这些重载只是有点痛苦 - 然后你意识到你需要双倍的区域
              【解决方案9】:

              很遗憾,无法获取路由的路由名称,因为该名称不是 Route 的属性。向 RouteTable 添加路由时,名称用作路由的内部索引,并且永远不会暴露。

              有一种方法可以做到这一点。

              当你注册一个路由时,在路由上设置一个带有路由名称的 DataToken 并使用它来过滤路由。

              #1 最简单的方法可能是编写自己的扩展方法来映射路由。

              【讨论】:

              • @Simon_Weaver Name 仍然不是 MVC 4 中的属性
              • 在 MVC 5 中仍然不是 Route 的属性!
              【解决方案10】:

              我一直面临着同样的困境,我得出的结论是,不幸的是,似乎没有办法找出 ASP.NET 选择使用哪条路由(按其名称)。

              您似乎只能通过路由中可能存在的参数名称来判断这一点 - 这些将显示在 RouteData.Values 字典中。

              如果有人知道某种方法可以获取 ASP.NET 为给定 URL 选择的路由的实际名称,我也很想知道如何自己做!

              【讨论】:

              • 是的,太臭了!他们有一个包含名称和路线的私人地图,但无法公开它:(
              • 其实,Haacked 的解决方案效果很好,现在在我的生产站点中 :)
              • @Andrey:是的,但它是一个黑客 :-) 我真的更喜欢一个“正确”的版本,而不必自己设置 DataTokens - 只是为了获得路线的名称......
              猜你喜欢
              • 1970-01-01
              • 2015-02-15
              • 1970-01-01
              • 2019-09-20
              • 2020-04-02
              • 2015-02-12
              • 1970-01-01
              • 2015-09-14
              • 2023-03-10
              相关资源
              最近更新 更多