31 votes

Comment empêcher Url.RouteUrl (...) d'hériter des valeurs de route de la demande en cours

Note: je vais répondre à ma propre question immédiatement ci-dessous

Disons que vous avez une méthode d'action pour l'affichage des produits dans un panier

 // ProductsController.cs
 public ActionMethod Index(string gender) {

      // get all products for the gender
 }

Par ailleurs, dans un entête qui est affiché sur chaque page que vous êtes en utilisant Url.RouteUrl créer HREF des liens vers d'autres pages sur le site :

 <a href="<%= Url.RouteUrl("testimonials-route", new { }) %>" All Testimonials </a>

Cette testimonials-route est définie en global.ascx par le premier itinéraire ci-dessous. Notez que l'appel ci-dessus à l' RouteUrl ne fournissent pas un gender, mais l'itinéraire est défini avec une valeur par défaut de "neutre", donc nous nous attendons à des Témoignages.Index("neutre") d'être appelé.

 routes.MapRoute(
  "testimonials-route",
  "testimonials/{gender}",
  new { controller = "Testimonials", action = "Index", gender = "neutral" },
  new { gender = "(men|women|neutral)" }
 );

routes.MapRoute(
  "products-route",
  "products/{gender}",
  new { controller = "Products", action = "Index", gender = (string)null },
  new { gender = "(men|women|neutral)" }
 );

Si quelqu'un visite la page /products/women , nous obtenons un HREF aux /testimonials/women Si quelqu'un visite la page /products alors nous obtenons un HREF vide (l'appel à RouteUrl renvoie la valeur null).

Mais cela ne fait pas sens y a-t-il? testimonials-route est supposé par défaut 'neutral' pour nous si nous ne fournissons pas de la route de la valeur pour elle?

Ce qu'il se passe, c'est qu' Url.RouteUrl(routeName, routeValues) helper extension va d'abord chercher dans ses routeValues de paramètre à un gender route de la valeur et si il ne le trouve pas dans le dictionnaire, il va chercher à l'URL courante que nous sommes (rappelez-vous que l'Url est un UrlHelper objet qui a le contexte actuel de la demande à sa disposition).

Cela a, éventuellement, un bel effet de nous donner un lien pour hommes témoignages si nous sommes sur un mens page du produit, mais que, probablement, n'est pas ce que nous voulons si nous n'avons pas adopté une valeur en RouteUrl appel, et explicitement spécifié "neutre" comme un défaut dans l' global.asax.cs le fichier.

Dans le cas où nous avons visité /products/ nous avons déclenché l' 'products-route' route et l' Products(null) méthode a été appelée. L'appel à l' Url.RouteUrl() fait hérite de CETTE valeur null pour gender lorsque nous sommes en train de créer une URL à l'aide d' testimonials-route. Même si nous avons spécifié une valeur par défaut pour gender en 'testimionials-route' il utilise toujours cette valeur null, ce qui provoque la route à l'échec et à l' RouteUrl renvoie la valeur null. [note: l'itinéraire échoue parce que nous avons une contrainte sur (hommes|femmes|neutre) et null ne rentre pas qu']

Il y a de plus effrayant dans ce "contrôleur" et "action", qui peut être transmis de la même manière. Cela peut conduire à des Url générées complètement le mauvais contrôleur de même lors de l'appel de RouteUrl(...) explicite le nom de l'itinéraire qui a un contrôleur par défaut.

Dans ce cas, une fois que vous avez compris, vous pouvez y remédier assez facilement dans de nombreuses façons, mais il pourrait dans d'autres cas, la cause de certains comportements dangereux. Cela peut être par la conception, mais sa certainement effrayant.

26voto

Simon_Weaver Points 31141

Ma solution était la suivante:

Une méthode d'assistance HtmlExtension:

     public static string RouteUrl(this UrlHelper urlHelper, string routeName, object routeValues, bool inheritRouteParams)
    {
        if (inheritRouteParams)
        {
            // call standard method
            return urlHelper.RouteUrl(routeName, routeValues);
        }
        else
        {
            // replace urlhelper with a new one that has no inherited route data
            urlHelper = new UrlHelper(new RequestContext(urlHelper.RequestContext.HttpContext, new RouteData()));
            return urlHelper.RouteUrl(routeName, routeValues);
        }
    }
 

Je peux maintenant faire:

 Url.RouteUrl('testimonials-route', new { }, false)
 

et sachez qu'il se comportera toujours de la même manière quel que soit le contexte.

La façon dont cela fonctionne est de prendre le UrlHelper existant et d'en créer un nouveau avec 'RouteData' vierge. Cela signifie qu'il n'y a rien à hériter (même une valeur nulle).

2voto

weirdlover Points 3493

Peut-être que je manque quelque chose ici, mais pourquoi ne pas l'installer comme ceci:

Dans votre asax global, créez deux itinéraires:

 routes.MapRoute(
    "testimonial-mf",
    "Testimonials/{gender}",
    new { controller = "Testimonials", action = "Index" }
);

routes.MapRoute(
    "testimonial-neutral",
    "Testimonials/Neutral",
    new { controller = "Testimonials", action = "Index", gender="Neutral" }
);
 

Ensuite, utilisez Url.Action au lieu de Url.RouteUrl:

 <%= Url.Action("Testimonials", "Index") %>
<%= Url.Action("Testimonials", "Index", new { gender = "Male" }) %>
<%= Url.Action("Testimonials", "Index", new { gender = "Female" }) %>
 

Ce qui, sur ma machine, résout les URL suivantes:

 /Testimonials/Neutral 
/Testimonials/Male 
/Testimonials/Female
 

Je ne sais pas si c'est une solution acceptable, mais c'est une alternative, non?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X