2009-09-26 10 views
18

Esiste un modo semplice per convertire l'URL della stringa nella raccolta RouteValueDictionary? Alcuni metodi come UrlToRouteValueDictionary(string url).Stringa URL a RouteValueDictionary

Ho bisogno di tale metodo perché voglio analizzare l'URL in base alle impostazioni dei miei percorsi, modificare alcuni valori di route e utilizzare urlHelper.RouteUrl() generare URL di stringa in base alla raccolta RouteValueDictionary modificata.

Grazie.

risposta

36

Ecco una soluzione che non richiede beffardo:

var request = new HttpRequest(null, "http://localhost:3333/Home/About", "testvalue=1"); 
var response = new HttpResponse(new StringWriter()); 
var httpContext = new HttpContext(request, response); 
var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext)); 
var values = routeData.Values; 
// The following should be true for initial version of mvc app. 
values["controller"] == "Home" 
values["action"] == "Index" 

Speranza questo aiuta.

+0

Piotr, grazie mille per l'aiuto. Questa soluzione sembra fantastica – Roman

+2

Qualcuno ha già scritto questo: [Creazione di un'istanza RouteData da un URL] (http://www.scottschluer.com/creating-a-routedata-instance-from-a-url/) –

+0

@ david.s Ho avuto problemi con la soluzione che hai postato. Non è stato possibile separare un valore di rotta da querystring. La soluzione di Piotr funziona bene. –

3

È necessario creare un HttpContext fittato come richiesto dai route.

Ecco un esempio che uso per unità di testare le mie vie (è stato copiato da Pro ASP.Net MVC framework):

 RouteCollection routeConfig = new RouteCollection(); 
     MvcApplication.RegisterRoutes(routeConfig); 
     var mockHttpContext = new MockedHttpContext(url); 
     RouteData routeData = routeConfig.GetRouteData(mockHttpContext.Object); 
     // routeData.Values is an instance of RouteValueDictionary 
     //... 
+0

Grazie, questa soluzione sembra interessante. Ma è un peccato che non ci sia un metodo "leggero" che non richiede il mocking, perché io uso Mock nei miei test unitari ma non nel codice generale. Sembra che dovrei. – Roman

+0

Ho avuto preoccupazioni simili e alla fine ho deciso di passare la RouteCollection serializzata tra le richieste. –

+0

Perfetto. Grazie mille. –

0

Ecco una soluzione che non richiede l'istanziazione di una serie di nuove classi.

var httpContext = context.Get<System.Web.HttpContextWrapper>("System.Web.HttpContextBase"); 
var routeData = System.Web.Routing.RouteTable.Routes.GetRouteData(httpContext); 
var values = routeData.Values; 
var controller = values["controller"]; 
var action = values["action"]; 

Il contesto di owin contiene un ambiente che include HttpContext.

+0

puoi spiegare un po 'di più il tuo contesto owin? Stai dicendo che lo snippet funziona se facciamo riferimento alle librerie Microsoft.Owin? – bkwdesign

+0

Sto eseguendo il codice sopra in un progetto MVC che utilizza OWIN. MVC 5 utilizza OWIN ma le versioni precedenti no. Se si utilizza MVC 5 o successivo, non è necessario aggiungere alcun riferimento. –

0

Non mi affido a RouteTable.Routes.GetRouteData dagli esempi precedenti perché in tal caso si rischia di perdere alcuni valori (ad esempio se i parametri della stringa di query non si adattano completamente a nessuno dei percorsi di mapping registrati). Inoltre, la mia versione non richiede il mocking di un gruppo di oggetti richiesta/risposta/contesto.

public static RouteValueDictionary UrlToRouteValueDictionary(string url) 
{ 
    int queryPos = url.IndexOf('?'); 

    if (queryPos != -1) 
    { 
     string queryString = url.Substring(queryPos + 1); 
     var valuesCollection = HttpUtility.ParseQueryString(queryString); 
     return new RouteValueDictionary(valuesCollection.AllKeys.ToDictionary(k => k, k => (object)valuesCollection[k])); 
    } 

    return new RouteValueDictionary(); 
}