如何从 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 获取路线名称?的主要内容,如果未能解决你的问题,请参考以下文章

RouteData

Laravel:通过指定名称获取路线

Orchard源码分析(7.1):Routing(路由)相关

如何从 url 或路由数据中获取控制器类型和操作信息?

MVC基础知识

Laravel 5.1-5.8 中以前的路线名称