web-dev-qa-db-fra.com

Comment puis-je obtenir le nom de la route à partir de RouteData?

J'ai plusieurs itinéraires définis dans mon Global.asax; 

Lorsque je suis sur une page, je dois déterminer le nom de la route de la route en cours, car elle porte le menu de mon site. 

Comment cela peut-il être fait?

32
Andrey

Malheureusement, il n’est pas possible d’obtenir le nom de la route car celle-ci n’appartient pas à la Route. Lorsque vous ajoutez des itinéraires à RouteTable, le nom est utilisé comme index interne pour l'itinéraire et il n'est jamais exposé.

Il y a un moyen de faire ça.

Lorsque vous enregistrez une route, définissez un DataToken sur la route avec le nom de la route et utilisez-le pour filtrer les routes.

Le moyen le plus simple de faire # 1 est probablement d'écrire vos propres méthodes d'extension pour mapper des itinéraires.

21
Haacked

Si vous travaillez avec un petit sous-ensemble de routes importantes que vous devez vérifier (un cas spécial ou deux), vous pouvez simplement procéder comme suit:

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

Une raison courante pour avoir besoin du nom de la route est à des fins de débogage. Vous trouverez ci-dessous une méthode rapide et délicate, mais vous devrez ajouter chaque nom de route au tableau de noms. Cela devrait convenir au débogage, surtout si le code ne fonctionne pas pendant la production.

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

Pour tout ce qui va au-delà, prenez le temps (minimal) nécessaire pour la solution de @ haacked. 

10
Simon_Weaver

FWIW, étant donné que les extensions et l'exemple présentés par @Simon_Weaver sont basés sur MVC et que le message est étiqueté avec WebForms, j'ai décidé de partager mes méthodes d'extension basées sur 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;
    }

Alors maintenant, dans Global.asax.cs lorsque vous enregistrez vos routes, au lieu de faire comme routes.MapPageRoute (...) - utilisez plutôt la méthode d'extension et faites route.MapPageRouteWithName (...)

Ensuite, lorsque vous souhaitez vérifier l’itinéraire sur lequel vous vous trouvez, il suffit de faire Page.RouteData.GetRouteName ()

C'est tout. Aucune réflexion et les seules références codées en dur à "nom de la route" se trouvent dans les deux méthodes d'extension (qui pourraient être remplacées par un const si vous le souhaitiez vraiment).

9
kman

Voici une implémentation de la suggestion de @ haacked - avec également un simple tableau «rasoir» pour afficher les données de route.

Remarque: Vous n'avez peut-être pas compris que toutes les méthodes «MapRoute» standard sont en réalité des méthodes d'extension. Par conséquent, nous ne pouvons pas utiliser le même nom. Je viens de l'appeler 'MapRoute2', parce que c'est tout ce à quoi je peux penser.

Vous devez remplacer tous les appels vers MapRoute par un appel à MapRoute2, n'oubliez pas tous les fichiers AreaRegistration ainsi que global.asax.cs

Méthode d'extension:

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

Voici un fichier rasoir .cshtml que j'utilise pour afficher les informations de routage:

<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>
7
Simon_Weaver

Je voterais positivement sur la réponse de Simon_Weaver, mais malheureusement, je viens juste de rejoindre le groupe et je n'ai pas les points de réputation pour le faire.

En ajoutant à sa réponse, parce que c’était exactement ce que je cherchais, voici comment je le fais:

J'ai un enum public "PageRouteTable":

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

J'utilise cette énumération lors de la construction des routes: 

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

J'ai ensuite créé une méthode d'extension de page:

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

Maintenant, dans mes pages, je peux simplement utiliser un interrupteur pour agir dessus:

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

J'ai aussi l'avantage de variables explicitement définies et je n'ai pas à m'inquiéter de coder avec des chaînes. Cela me sauve une tonne de maux de tête en maintenance.

- codage heureux.

6
MikeAtCodeSmart

RouteCollection maintient un dictionnaire privé d'itinéraires nommés.

Les noms d’itinéraires peuvent être récupérés par

  1. en utilisant la réflexion pour récupérer la valeur du champ privé et
  2. interroger le dictionnaire pour l'élément dont la valeur est la route.

La méthode d'extension ci-dessous suit ce processus:

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;
}
3
Samu Lang

Pour C #, vous pouvez déclarer vos itinéraires comme suit:

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

Ensuite, dans votre méthode où vous avez besoin de la route, vous pouvez appeler le suivant:

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

Et vous aurez une chaîne définie dans votre global.asax à utiliser selon vos besoins.

2
Andrew Berry

J'ai été confronté au même dilemme et je suis parvenu à la conclusion que, malheureusement, il ne semble pas y avoir de moyen de savoir quelle route (par son nom) ASP.NET a choisi d'utiliser.

Il semble que vous ne puissiez le comprendre que par les noms des paramètres pouvant exister dans votre itinéraire. Ceux-ci figureront dans le dictionnaire RouteData.Values.

Si quelqu'un connaît un moyen d'obtenir le nom réel de la route choisie par ASP.NET pour une URL donnée, je serais intéressé de savoir comment le faire moi aussi!

1
marc_s

Vous pouvez ajouter tous les paramètres de route et il n'est pas nécessaire que ces paramètres soient dans votre URL: Vous pouvez mettre le nom de votre route en tant que paramètre de la manière suivante:

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

Et accédez-y dans votre page:

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

               }  

           }

Le meilleur moyen n’est pas difficile.

1
Farhawd

Une approche simple que j'ai mise en œuvre consiste à fournir une clé nommée pour le paramètre 'default' de la méthode .MapPageRoute. Utilisez une constante pour la valeur par défaut et vous pouvez l'extraire de la collection Page.RouteData.Values ​​de la même manière que vous le feriez normalement.

exemple (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") me donne 'stats'

0
ScottE