【发布时间】:2011-04-26 15:53:40
【问题描述】:
我在 Global.asax 中定义了几条路线;
当我在一个页面上时,我需要弄清楚当前路由的路由名称是什么,因为路由名称驱动着我的站点菜单。
如何做到这一点?
【问题讨论】:
标签: asp.net routing webforms url-routing
我在 Global.asax 中定义了几条路线;
当我在一个页面上时,我需要弄清楚当前路由的路由名称是什么,因为路由名称驱动着我的站点菜单。
如何做到这一点?
【问题讨论】:
标签: asp.net routing webforms url-routing
如果您正在处理需要检查的重要路线的一小部分(一两个特殊情况),您可以这样做:
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 解决方案所需的(最少)时间。
【讨论】:
您可以添加每个路由参数,而这些参数不必在您的 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"]);
}
}
最好的方法并不难。
【讨论】:
对于 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 中设置一个字符串,然后根据需要使用。
【讨论】:
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 替换)。
【讨论】:
我实现的一个简单方法是为 .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") 给我“统计数据”
【讨论】:
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;
}
【讨论】:
我会投票赞成 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;
.
.
.
}
}
我也有明确定义的变量的好处,不必担心针对字符串进行编码。这为我省去了很多维护方面的麻烦。
-- 快乐的编码。
【讨论】:
这是@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>
【讨论】:
很遗憾,无法获取路由的路由名称,因为该名称不是 Route 的属性。向 RouteTable 添加路由时,名称用作路由的内部索引,并且永远不会暴露。
有一种方法可以做到这一点。
当你注册一个路由时,在路由上设置一个带有路由名称的 DataToken 并使用它来过滤路由。
#1 最简单的方法可能是编写自己的扩展方法来映射路由。
【讨论】:
我一直面临着同样的困境,我得出的结论是,不幸的是,似乎没有办法找出 ASP.NET 选择使用哪条路由(按其名称)。
您似乎只能通过路由中可能存在的参数名称来判断这一点 - 这些将显示在 RouteData.Values 字典中。
如果有人知道某种方法可以获取 ASP.NET 为给定 URL 选择的路由的实际名称,我也很想知道如何自己做!
【讨论】: