2009-07-18 14 views
30

Diciamo che avere un metodo di azione per visualizzare i prodotti in un carrello della spesaCome prevenire Url.RouteUrl (...) di ereditare valori percorso dalla richiesta corrente

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

     // get all products for the gender 
} 

Altrove, in una testa d'albero che è visualizzati in ogni pagina che si sta utilizzando Url.RouteUrl per creare link HREF ad altre pagine del sito:

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

Questo testimonials-route è definito nel global.ascx dal primo percorso di seguito. Si noti che la precedente chiamata a RouteUrl non fornisce uno gender, ma il percorso è definito con un valore predefinito di "neutro", pertanto ci si aspetta che venga chiamato Testimonials.Index ("neutro").

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

Se qualcuno visita la pagina /products/women otteniamo un HREF per /testimonials/women Se qualcuno visita la pagina /products allora otteniamo un HREF vuoto (la chiamata a RouteUrl restituisce null).

Ma questo non ha senso, vero? testimonials-route è impostato per default su 'neutral' per noi se non forniamo un valore di percorso per questo?

Ciò che risulta sta accadendo è che Url.RouteUrl(routeName, routeValues) estensione aiutante cercherà prima nel suo parametro routeValues per un valore gender percorso e se non lo trova in questo dizionario si esaminerà l'URL corrente che siamo sulla (ricorda che Url è un oggetto UrlHelper che ha a disposizione il contesto della richiesta corrente).

Questo ha un effetto possibilmente bello di darci un link a testimonianze maschili se siamo su una pagina di prodotto uomo, ma che probabilmente non è quello che vogliamo se non abbiamo passato un valore nella chiamata RouteUrl, ed esplicitamente specificato 'neutro' come predefinito nel file global.asax.cs.

Nel caso in cui abbiamo visitato /products/, è stato attivato il percorso 'products-route' e il metodo è stato chiamato. La chiamata a Url.RouteUrl() eredita effettivamente QUESTO valore nullo per gender quando stiamo creando un URL utilizzando testimonials-route. Anche se abbiamo specificato un valore predefinito per gender in 'testimionials-route 'utilizza ancora questo valore nullo che causa il fallimento dell'itinerario e RouteUrl restituisce null. [nota: la rotta fallisce perché abbiamo un vincolo su (uomini | donne | neutrali) e null non corrisponde a questo]

In realtà diventa più spaventoso - in quanto "controller" e "azione" possono essere ereditati in allo stesso modo. Ciò può comportare la generazione di URL completamente al controller sbagliato anche quando si chiama RouteUrl (...) con un nome di route esplicito con un controller predefinito.

In questo caso, una volta individuato, è possibile risolverlo facilmente in molti modi, ma in altri casi potrebbe causare un comportamento pericoloso. Questo può essere di progettazione, ma è decisamente spaventoso.

+0

aggiungendo una taglia un anno e mezzo dopo la domanda originale perché (a) mi piacerebbe sapere se il framework ora fa questo per me e (b) sono molto curioso perché questo ha solo 2 upvotes. pensato che sarebbe un problema comune quindi chiedendo se sto facendo qualcosa di sbagliato! –

+0

questo è stato kicking il mio bootie, come il tag {domain} mancava un valore, ma che il sistema dovrebbe fornire automaticamente. Una volta cambiato, ha funzionato. –

+0

perché non chiami semplicemente RenderUrl come: '" '- quindi, niente viene sovrascritto . – Gerwald

risposta

26

La mia soluzione era questa:

Un metodo HtmlExtension helper:

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

Ora posso fare:

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

e so per certo che sarà sempre comportarsi allo stesso modo, non importa quale contesto.

Il modo in cui funziona è prendere lo UrlHelper esistente e crearne uno nuovo con "RouteData" vuoto. Ciò significa che non c'è nulla da ereditare (anche un valore nullo).

+0

mentre io sto bene con la mia soluzione - mi piacerebbe che ci fosse un modo per farla rispettare a livello globale, e non dover ricordare di usare sempre questo sovraccarico. si spera che MVC4 darà un maggiore controllo su questo. –

+0

Ho appena incontrato lo stesso identico problema. Questo è stato molto utile! Stavo pensando di estendere il metodo HtmlHelper.RouteLink per fare la stessa cosa per i collegamenti, ma sto avendo problemi a risolvere la sintassi per istanziare un nuovo HtmlHelper. – goombaloon

+0

Questa è una buona soluzione. Per noi questi collegamenti erano tutti nella stessa vista parziale, quindi ho solo istanziato il nuovo UrlHelper come variabile e ho usato quella variabile nel partial invece della proprietà Url standard. –

2

forse mi manca qualcosa qui, ma perché non configurarlo in questo modo:

Nella tua ASax globale, creare due percorsi:

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

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

Quindi, utilizzare Url.Action invece di URL .RouteUrl:

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

il che, sulla mia macchina risolve ai seguenti URL:

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

Non sono sicuro che questa sia una soluzione accettabile, ma è un'alternativa, no?

+0

sfortunatamente (o forse per fortuna!) Il problema non è nell'analisi e nell'instradamento dell'URL. funziona perfettamente come previsto - quindi il tuo primo percorso qui è sufficiente (se aggiungi un parametro predefinito). si trova nella creazione effettiva dell'URL quando i valori di instradamento esistenti vengono ereditati in modo imprevisto. la mia soluzione che uso da più di un anno - è semplicemente fastidiosa quando è necessario utilizzare altri overload di RouteUrl o RouteLink ed è necessario creare una tonnellata di overload di metodi. grazie per la risposta però –

Problemi correlati