2013-06-14 21 views
7

Obecnie eksperymentuję z punktami końcowymi OData w ASP.NET MVC 4 Web API. Podoba mi się ta koncepcja i staram się wymyślić skuteczne sposoby jej wykorzystania w naszym projekcie. Jedno pytanie mam jest następujący: mamy usługę, która jest w stanie zwrócić IQueryable i przyjmuje nazwę podmiotu jako wejście:ASP.NET WebAPI: kontroler ogólny dla punktu końcowego OData

public IQueryable GetAll(string entityName); 

W standardzie Web API (w przeciwieństwie do kontrolerów OData) mogę utwórz ogólny kontroler, który można wywołać w formularzu/api/entity/{entityName} i zwróci IQueryable. W przypadku kontrolera OData, I przeprowadzić następujące czynności podmiot specyficzne:

  1. zarejestrować podmioty w modelu.
  2. Utwórz oddzielny kontroler dla każdej jednostki, która pochodzi od EntitySetController <>.

Chcę używać usługi ogólnej i unikać jak największej liczby implementacji specyficznych dla jednostki. Pierwszy krok można łatwo zautomatyzować, jeśli usługa może zwrócić listę podmiotów i odpowiadające im typy. Zostawia to krok 2, ponieważ do tej pory muszę utworzyć określony kontroler dla każdej jednostki. Też chcę tego uniknąć i stworzyć ogólny kontroler, który używa ogólnej usługi.

Czy ktoś może polecić rozwiązanie, może wpływając na routing OData?

Odpowiedz

11

Można utworzyć niestandardową konwencję routingu, która wybierze ten sam kontroler bez względu na ustawiony obiekt. Przykład,

public class CustomControllerRoutingConvention : IODataRoutingConvention 
{ 
    public string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap) 
    { 
     return null; 
    } 

    public string SelectController(ODataPath odataPath, HttpRequestMessage request) 
    { 
     return "SomeFixedContrllerNameWithoutTheControllerSuffix"; 
    } 
} 

Można zarejestrować tę konwencję routingu za pomocą następującego kodu

IList<IODataRoutingConvention> routingConventions = ODataRoutingConventions.CreateDefault(); 
routingConventions.Insert(0, new CustomControllerRoutingConvention()); 
config.Routes.MapODataRoute("OData", "odata", builder.GetEdmModel(), new DefaultODataPathHandler(), routingConventions); 
+1

Należy sprawdzić odataPath dla elementów null. Oznacza to zapytania o dane meta, które muszą przejść do domyślnej trasy. if (odataPath.EdmType == null || odataPath.EntitySet == null) zwraca wartość null; – xt1

+0

To również rozwiązało problem z uzyskaniem v3 i v4 w tym samym projekcie, ponieważ nie można mieć zduplikowanych nazw kontrolerów, a próba użycia atrybutu route na innej nazwie kontrolera powoduje 406. Dla konwencji nazwy kontrolera EntityV4Controller, zwracając odataPath.NavigationSource.Name + "V4" znajdzie kontroler. –

+0

Metoda sprawdzania zapytań o metadane @ xt1 jest podobno powszechna, ale nie jest wiarygodna. Nasz projekt zawiera sytuacje, w których 'odataPath.EntitySet == null', ale nie jest to żądanie metadanych $. Odkryłem, że sprawdzanie połączenia 'ODataSegmentKinds.ServiceBase' i' ODataSegmentKinds.Metadata' jest bardziej niezawodne.(Dotyczy usługi V3.) –

6

wpadłem na ten sam problem, a skończyło się na piśmie zwyczaj IHttpControllerSelector zamiast IODataRoutingConvention. IODataRoutingConvention wygląda na dobrą opcję, jeśli Twój ogólny kontroler nie wymaga generics :). Ale ponieważ IODataRoutingConvention.SelectController() zwraca tylko ciąg, nie widzę, jak to będzie działać do tworzenia instancji kontrolera z ogólnych parametrów typu.

Zdecydowałem, że ten problem wymaga dobrego, uniwersalnego rozwiązania o otwartym kodzie źródłowym - dlatego stworzyłem: http://entityrepository.codeplex.com. Jest teraz w fazie wstępnej, ale obecnie dużo nad nim pracuję. Myślę, że jest w tym coś więcej niż tylko wybór odpowiedniego kontrolera, istnieją ogólne wzorce do zdefiniowania dla współdzielonych kontrolerów, a domyślnie ODMA Web API oczekuje silnie typowanych i silnie nazwanych właściwości nawigacyjnych, co sprawia, że ​​trudno jest stworzyć implementację wielokrotnego użytku.

Powiązane problemy