2009-09-26 10 views
18

Czy istnieje prosty sposób konwersji adresu URL ciągów do kolekcji RouteValueDictionary? Niektóre metody, takie jak UrlToRouteValueDictionary(string url).Ciąg URL do RouteValueDictionary

Potrzebuję takiej metody, ponieważ chcę "parsować" URL zgodnie z ustawieniami moich tras, modyfikować niektóre wartości tras i za pomocą urlHelper.RouteUrl() generować ciąg adresu URL zgodnie ze zmodyfikowaną kolekcją RouteValueDictionary.

Dzięki.

Odpowiedz

36

Oto rozwiązanie, które nie wymaga szydząc:

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" 

Nadzieja to pomaga.

+0

Piotr, dziękuję bardzo za pomoc. To rozwiązanie wygląda świetnie – Roman

+2

Ktoś już to napisał: [Tworzenie instancji RouteData z adresu URL] (http://www.scottschluer.com/creating-a-routedata-instance-from-a-url/) –

+0

@ david.s Miałem problemy z rozwiązaniem, które opublikowałeś. Nie można ustawić wartości trasy z zapytania o znak zapytania. Rozwiązanie Piotra działa dobrze. –

3

Będziesz musiał utworzyć wyszydzony HttpContext, ponieważ wymaga tego ograniczenie trasy.

Oto przykład, który używam do jednostki przetestować moje trasy (został on skopiowany z 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

Dzięki temu rozwiązanie wygląda interesująco. Ale szkoda, że ​​nie ma "lekkiej" metody, która nie wymaga kpiny, ponieważ używam Mocks w moich testach jednostkowych, ale nie w ogólnym kodzie. Wygląda na to, że powinienem. – Roman

+0

Miałem podobne obawy i ostatecznie zdecydowałem się przekazać szeregową RouteCollection między żądania. –

+0

Idealny. Dziękuję bardzo. –

0

Oto rozwiązanie, które nie wymaga tworzenia nowych klas.

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"]; 

owin kontekst zawiera środowisko obejmuje HTTPContext.

+0

Czy możesz wyjaśnić nieco swój kontekst związany z owacjami? Czy mówisz, że twój fragment kodu działa, jeśli odnosimy się do bibliotek Microsoft.Owin? – bkwdesign

+0

Uruchomiłem powyższy kod w projekcie MVC, który używa OWIN. MVC 5 używa OWIN, ale wcześniejsze nie. Jeśli używasz MVC 5 lub nowszego, nie powinieneś dodawać żadnych odniesień. –

0

Nie będę polegał na RouteTable.Routes.GetRouteData z poprzednich przykładów, ponieważ w takim przypadku ryzykujesz utratę niektórych wartości (na przykład, jeśli parametry ciągu zapytania nie w pełni pasują do zarejestrowanych tras mapowania). Moja wersja nie wymaga też kpiny z obiektów żądania/odpowiedzi/kontekstu.

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(); 
} 
Powiązane problemy