如何从 RouteData 获取路线名称?
Posted
技术标签:
【中文标题】如何从 RouteData 获取路线名称?【英文标题】:How do I get Route name from RouteData? 【发布时间】:2011-04-26 15:53:40 【问题描述】:我在 Global.asax 中定义了几条路线;
当我在一个页面上时,我需要弄清楚当前路由的路由名称是什么,因为路由名称驱动着我的站点菜单。
如何做到这一点?
【问题讨论】:
【参考方案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 维护着一个命名路由的私有字典。
路线名称可以通过
-
使用反射检索私有字段的值并
在字典中查询其值为路由的项。
下面的扩展方法遵循这个过程:
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 - 只是为了获得路线的名称......以上是关于如何从 RouteData 获取路线名称?的主要内容,如果未能解决你的问题,请参考以下文章