2016-03-10 12 views
10

Istniejący projekt ma sterowników, które dziedziczą z albo:Get URL z nazwami ApiController i działania, w projekcie zawierającym Kontrolery i ApiControllers

  • Controller: RouteTable.Routes.MapRoute z "{controller}/{action}/{id}".
  • ApiController: GlobalConfiguration.Configure oraz w oddzwonieniu MapRoute z "api/{controller}/{id}".

Wszystko działa dobrze, ale muszę wygenerować adresy URL dla metod działania w obu tych typach kontrolerów. Biorąc pod uwagę:

  1. nazwę lub typ kontrolera, która dziedziczy z jednej z nich, a
  2. nazwa metody działania

Wtedy od strony witryny internetowej, w jaki sposób mogę wygenerować odpowiednie adresy URL strona interfejsu API sieci?

Używam refleksji, aby uzyskać nazwy akcji i kontrolerów już teraz, a następnie poprzez użycie UrlHelper.Action(actionName, controllerName, routeValueDictionary) otrzymuję poprawny adres URL dla tras witryny internetowej.

Jednak ta metoda (oczywiście) generuje adresy URL takie jak dla strony WebAPI: /ApiControllerName/Get?parameter1=value, kiedy musi być /api/ApiControllerName?parameter1=value i osobna wiedza, że ​​jest to żądanie GET.

Cel: jest to strona z testem dymu dla strony internetowej, która używa atrybutów i refleksji, aby zdecydować, co testować. Byłoby miło móc używać tego samego atrybutu w całym projekcie, a ponadto byłoby bardzo miło móc użyć poprawnego UrlHelper, który zna tabele routingu i może wytworzyć właściwy prefiks, taki jak /api/, zamiast kod zakładający, być może błędnie, że trasy API zostały zarejestrowane pod numerem api, a nie, powiedzmy, webapi.

Aktualizacja

Po kontynuacji badań znalazłem the Url.HttpRouteUrl method które mogą generować WebAPI adresy URL, ale wymaga to znając nazwę trasy, a nie nazwa metody działania.

Zrobiłem jeszcze więcej badań na ten temat i nie zbliżyłem się do rozwiązania. Wygląda na to, że znasz nazwę trasy odpowiedniej trasy, you can cook up a Url easily. Istnieją również pewne prawdopodobne wskazówki: here i here. Ale jeśli istnieje wiele tras dla WebApi, skąd wiadomo, który pasuje do kontrolera i działania, które chcesz? Byłoby głupie, by ponownie wprowadzić w życie to, co MVC już robi, wybierając kontroler i działanie. Myślę, że mógłbym stworzyć adres URL z podanych parametrów przy użyciu każdej trasy WebApi, a następnie uruchomić adres URL za pomocą jego kroków (używając niektórych z powyższych linków) i sprawdzić, czy pasuje do pożądanego kontrolera ... fuj.

Musi być łatwiejszy sposób.

Na razie będę musiał przejść, ale mam nadzieję, że ktoś mi pomoże.

Odpowiedz

5

Oto kilka sposobów zrobić:

  • Korzystanie RouteUrl() metodę:

    var url1 = Url.RouteUrl(new { id = 1, controller = "...", httproute = true }); 
    

Sztuką jest oczywiście httproute = true. Ustawiając tę ​​właściwość, informujesz, że chcesz tylko tras http (trasy Web Api).

  • Korzystanie HttpRouteUrl() metody:

    var url2 = Url.HttpRouteUrl(null, new { id = 2, controller = ".." }); 
    
  • a inny sposób to zrobić korzystając bezpośrednio z trasy i httproute wartość:

    var values = new RouteValueDictionary(new 
    { 
        id = 3, 
        controller = "...", 
        httproute = true 
    }); 
    var url3 = RouteTable.Routes.GetVirtualPath(Request.RequestContext, values).VirtualPath; 
    

Do 3 sposoby są zasadniczo takie same . Ponieważ nie określisz trasy, system spróbuje znaleźć pierwsze dopasowanie zgodnie z wartościami trasy. Na przykład, powiedzmy, że masz ApiController nazywa RestfulController i Web API trasy są skonfigurowane w taki sposób:

config.Routes.MapHttpRoute(
    name: "DefaultApi", 
    routeTemplate: "api/{controller}/{id}", 
    defaults: new { id = RouteParameter.Optional } 
); 

Korzystanie z pierwszej metody, kiedy robisz var url = Url.RouteUrl(new { id = 123, controller = "restful", httproute = true }); w MVCController wartość w url jest /api/restful/123.

Ale jeśli dodać nową trasę ConstraintApi:

config.Routes.MapHttpRoute(
    name: "ConstraintApi", 
    routeTemplate: "api2/{controller}/{id}", 
    defaults: new { id = RouteParameter.Optional }, 
    constraints: new { controller = "restful" } 
); 

config.Routes.MapHttpRoute(
    name: "DefaultApi", 
    routeTemplate: "api/{controller}/{id}", 
    defaults: new { id = RouteParameter.Optional } 
); 

Adres URL jest zwracany przez RouteUrl/api2/restful/123.

Powinieneś znać kolejność zgłaszania tras. Jeśli przed trasą ConstraintApi zostanie dodana trasa DefaultApi, wygenerowany adres URL to /api/restful/123.

+0

Działa, z niewielkim wyjaśnieniem. dla 'httproute = false', należy użyć' UriHelper.Action' i przekazać nazwę metody działania jako parametr, a nie umieścić go w 'RouteValuesCollection'. Ponadto, w WebApi, jest trochę zabawy z prawidłowym odgadywaniem czasownika HTTP, ale na razie jestem usatysfakcjonowany (przekazywanie w 'action =" Get "' lub 'action =" MethodName "' po prostu wyświetla wartość zapytania). – ErikE

3

Istnieje biblioteka Hyprlinkr, która umożliwia tworzenie identyfikatorów URI z kontrolera i działania przy użyciu konfiguracji trasy.

+0

To wygląda interesująco i może okazać się dokładnie tym, czego potrzebuję, ale w międzyczasie nie jest gotowe do pracy po wyjęciu z pudełka, ponieważ "wymaga instancji klasy" HttpRequestMessage ", która jest dostarczana przez ASP. NET Web API dla każdego żądania. Preferowanym sposobem uzyskania tej instancji jest zaimplementowanie niestandardowego "IHttpControllerActivator" i utworzenie tam instancji RouteLinker. " Oznacza to, że będę musiał zrobić coś sprytnego, aby działał po stronie internetowej (co oczywiście nie jest łatwe z instancją 'HttpRequestMessage'). – ErikE

0

To wydaje się bardziej jak hak, ale warto spróbować, jeśli planujesz go użyć tylko do testowania. Jak wspomniano, możesz wygenerować adres URL z nazwą trasy. Możesz więc pobrać wszystkie nazwy tras i wygenerować wszystkie możliwe adresy URL. Następnie musisz sprawdzić, czy URL odpowiada na akcję, której potrzebujesz, czy nie. Do tego możesz użyć czegoś takiego: https://stackoverflow.com/a/19382567/1410281. Podstawową ideą jest to, że jeśli masz adres URL, wykonaj fałszywe przekierowanie i pobierz dane routingu z frameworka.

+0

To interesujący pomysł. W jaki sposób parametry będą w niego odtwarzane, to znaczy, gdy metody działania różnią się tylko w zależności od listy parametrów, w jaki sposób mogę niezawodnie wygenerować adres URL, który uderzy w pożądaną metodę działania? Co się stanie, jeśli trasy zostały ustawione bez nazw tras? – ErikE

+0

Jak już powiedziałem, nie jest to pełne rozwiązanie, ale raczej hackowanie.Parametry będą działały tak daleko, jak to możliwe, z refleksją i najprawdopodobniej będą działać tylko w przypadkach, które są potrzebne. (Wspomniałeś w swojej aktualizacji, że możliwe jest wygenerowanie adresu URL, jeśli masz nazwę trasy, więc po prostu uznałem, że możesz rozwiązać ten problem) – Tamas

+0

Jeśli chodzi o trasy, które nie mają nazw, możesz utworzyć własne 'Route' i' RouteCollection 'class, która przechowuje nazwę trasy lub gdy nie jest określone nic, niż generuje taką, do której można się odnosić. – Tamas