2015-11-06 19 views
5

Mam działający (uproszczony) ODataController za pomocą następującej metody.Jak utworzyć instancję ODataQueryOptions

public class MyTypeController : ODataController 
{ 
    [HttpGet] 
    [EnableQuery] 
    [ODataRoute("myTypes")] 
    public IQueryable<MyType> GetMyTypes(ODataQueryOptions<MyType> options) 
    { 
    return _repo.myResultsAsQueryable(); 
    } 
} 

Chciałbym móc wywołać tę metodę z serwera i do tego muszę instancję ODataQueryOptions która wymaga ODataQueryContext zrobić.

Istnieją przykłady, jak to zrobić (np. here i here), ale wszystkie wydają się odwoływać do poprzedniej wersji OData. Konstruktor ODataQueryContext wymaga obecnie trzeciego argumentu (ścieżka ODataPath), który nie jest opisany w żadnych przykładach, które można znaleźć.

Edit: @snow_FFFFFF, Oto niektóre więcej kontekst ... Zdaję sobie sprawę, że mogę po prostu zużywają końcowy OData za pośrednictwem HttpClient ale chciałbym wchodzić w interakcje z IQueryable bezpośrednio jak mówisz.

Problem polega na tym, że aplikacja, nad którą pracuję, umożliwia użytkownikom tworzenie filtrów (takich jak wyrafinowana wyszukiwarka), które można zapisać i później przywołać przez innych użytkowników. Z klienta JS po prostu wyszukują filtr według identyfikatora i wysyłają zapytanie do punktu końcowego OData z filtrem zastosowanym do ciągu zapytania. Działa to bardzo dobrze od strony klienta, ale chciałbym móc zrobić coś podobnego również po stronie serwera.

To jest to, co chciałbym zrobić, ale jak mogę utworzyć argument ODataPath?

public IQueryable<MyType> FilterMyTypes(int filterID) 
{ 
    // lookup filter by filterID from db... 
    filter = "$filter=Status eq 1"; // for example... 

    ODataPath path = // but how can I get the path!!! 
    new ODataQueryContext(edmModel, typeof(MyType), path); 

    var uri = new HttpRequestMessage(HttpMethod.Get, "http://localhost:56339/mytypes?" + filter); 
    var opts = new ODataQueryOptions<MyType>(ctx, uri); 

    var results = new MyTypeController().GetMyTypes(opts); 
} 

Innym zastosowaniem byłoby wspieranie dynamicznego grupowania jak poniżej:

[HttpGet] 
[Route("myTypes/{filterID:int}/groupby/{groupByFieldName}")] 
public IHttpActionResult GroupMyTypes(int filterID, string groupByFieldName) 
{ 
    // For example: get all Active MyTypes and group by AssignedToUserID... 

    // Get the results of the filter as IQueryable... 
    var results = FilterMyTypes(filterID); 

    // group on groupByFieldName 
    var grouped = results.GroupBy(x => GetPropertyValue(x,groupByFieldName)); 

    // select the groupByFieldName and the count 
    var transformedResults = grouped.Select(g => new { g.Key, Count = g.Count() }); 

    return Ok(transformedResults); 
} 
+1

W http://github.com/OData/WebApi można znaleźć wiele przypadków testowych. Na przykład ODataQueryContext, można przejść do: https://github.com/OData/WebApi/blob/master/OData/test/UnitTest/System.Web.OData.Test/OData/Query/ODataQueryContextTests.cs#L181- L200 –

+0

Dzięki Sam, spróbuję tego .. Nie przyzwyczaiłem się do MS z otwartym źródłem ... –

+0

Sam. Jesteś niesamowity! Jeśli umieścisz to w odpowiedzi, mogę to zaakceptować. Dzięki wielkie. Pracował jak urok. –

Odpowiedz

3

Jasne. ODataPath jest listą ODataPathSegment (s), która powinna nastąpić po OData Uri spec.

W Web API OData, łatwo instancję ODataPath, na przykład:

IEdmModel model = GetEdmModel(); 
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet(setName); 
ODataPath path = new ODataPath(new EntitySetPathSegment(entitySet)); 

Powyższy path zagryzieni spec OData że ma OData szablon jako:

~/entityset 

Więcej Przypadki testowe (kody) można znaleźć here

+1

Na dzień 25.05.2017 najnowszą stabilną wersją 'Microsoft.AspNet.OData' jest wersja 6.0.0. Wygląda na to, że nie ma już klasy 'EntitySetPathSegment'. Musiałem zmienić wersję NuGet na 5.9.1. W przeciwnym razie BARDZO pomocne pytanie, a ja naprawdę doceniłem link do przypadków testowych kodu źródłowego. – asporter

+0

zakorkowany link na dzień dzisiejszy. –

0

Twój OData kontroler zapewnia interfejs HTTP do swoich danych, nie należy do niego dostęp za pośrednictwem protokołu HTTP (nawet jeśli z serwera)? Jest VS dodatek do generowania OData kod klienta tutaj:

https://visualstudiogallery.msdn.microsoft.com/9b786c0e-79d1-4a50-89a5-125e57475937

Lub, jeśli robisz to z ramach tego samego projektu, to dlaczego nie wspólnej metody, która zwraca IQueryable, które mogą być wywoływane z Twój kod lub od kontrolera?

UPDATE: Na podstawie dalszych informacji na oryginalne pytanie:

Jeśli masz ODataQueryOptions zdefiniowane w metodzie kontrolera, pozwoli Ci przeanalizować dobrze uformowane zapytanie OData że jest wywołanie tej metody. Używałem tego, kiedy musiałem tłumaczyć części zapytania odata, ponieważ musiałem wysyłać zapytania do wielu źródeł danych, aby zwrócić ostateczny wynik.

Wygląda na to, że chcesz coś, co bierze parametry i opcje inne niż odata. Do tego, to prawdopodobnie trzeba spojrzeć na niestandardowych działaniach i czy funkcje (jeśli tylko zwracania danych, prawdopodobnie funkcja):

http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/odata-actions-and-functions

UPDATE # 2: A po bardziej szczegółowym czytania, myślę Brakowało mi twojej racji - nie mam odpowiedzi, ale będę się z nią bawił. Nie możesz po prostu zreformować samego adresu URL (w przeciwieństwie do tworzenia zapytań o opcje?

Aktualizacja # 3: Myślę, że masz zamiar mieć twardy czas nakłanianiu go do myślenia, że ​​jest coraz OData wniosku ... że nie jest tak naprawdę OData żądanie. Powrót do drugiej opcji, o którym mowa w moim pierwotnym odpowiedź - dlaczego nie jest to popularna metoda, które można wykorzystać i OData kontroler może użyć - coś takiego:

// some sort of helper class 
public class HelperObject 
{ 
    public static IQueryable<MyType> GetGroupedValues(int filterID, string groupByFieldName) 
    { 
     // all your code/logic here 
    } 
} 

// your odata controller uses the helper 
[HttpGet] 
[Route("myTypes/{filterID:int}/groupby/{groupByFieldName}")] 
public IHttpActionResult GroupMyTypes(int filterID, string groupByFieldName) 
{ 
    return Ok(HelperObject.GetGroupedValues(filterID, groupByFieldName)); 
} 

// ... and so does your other code that wants to do the same thing 
var x = HelperObject.GetGroupedValues(filterID, groupByFieldName); 
Powiązane problemy