2015-11-06 21 views
5

Ho un lavoro (semplificato) ODataController con il seguente metodo.Come istanziare ODataQueryOptions

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

Vorrei essere in grado di chiamare questo metodo dal server e per fare questo ho bisogno di creare un'istanza di un ODataQueryOptions che richiede un ODataQueryContext.

Esistono esempi di come eseguire questa operazione (ad esempio here e here) ma sembrano tutti fare riferimento a una versione precedente di OData. Il costruttore ODataQueryContext richiede attualmente un terzo argomento (percorso ODataPath) che non è indirizzato in nessun esempio che riesca a trovare.

Edit: @snow_FFFFFF, ecco un po 'di contesto ... mi rendo conto che posso semplicemente consumare l'endpoint OData tramite un HttpClient ma vorrei interagire con l'IQueryable direttamente come dici tu.

Il problema è che l'applicazione su cui sto lavorando consente agli utenti di creare filtri (come un motore di ricerca sofisticato) che possono essere salvati e successivamente richiamati da altri utenti. Da un client JS, cercano semplicemente il filtro per id e inviano una query sull'endpoint OData con il filtro applicato alla stringa di query. Funziona molto bene dal lato client, ma mi piacerebbe essere in grado di fare qualcosa di simile anche dal lato server.

Questo è ciò che mi piacerebbe fare, ma come posso creare un'istanza dell'argomento 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); 
} 

Un'altra applicazione di questo sarebbe per sostenere il raggruppamento dinamico come di seguito:

[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

In http://github.com/OData/WebApi, ci sono molti casi di test a cui è possibile fare riferimento. Ad esempio, ODataQueryContext, è possibile fare riferimento a: https://github.com/OData/WebApi/blob/master/OData/test/UnitTest/System.Web.OData.Test/OData/Query/ODataQueryContextTests.cs#L181- L200 –

+0

Grazie Sam, ci proverò .. Non usato per MS con open source ... –

+0

Sam. Sei fantastico! Se lo metti in una risposta, posso accettarlo. Grazie mille. Ha funzionato come un fascino. –

risposta

3

Certo. ODataPath è una lista di ODataPathSegment (s) che dovrebbe seguire il OData Uri spec.

In Web API OData, è facile creare un'istanza di un ODataPath, ad esempio:

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

È possibile che questo path segue la spec OData che ha il modello odata come:

~/entityset 

Altro casi di test (codici) possono essere trovati here

+1

A partire da 1/25/2017 l'ultima versione stabile di 'Microsoft.AspNet.OData' è v6.0.0. Sembra che non esista più una classe 'EntitySetPathSegment'. Ho dovuto effettuare il downgrade in NuGet alla 5.9.1. In caso contrario, MOLTA domanda utile, e ho davvero apprezzato il link ai casi di test del codice sorgente. – asporter

+0

link borked a partire da oggi. –

0

Il controller odata sta fornendo un'interfaccia HTTP ai vostri dati, non si dovrebbe accedere tramite HTTP (anche se dal server)? C'è un VS add-in per generare il codice client odata qui:

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

O, se si sta facendo questo da all'interno dello stesso progetto, perché non un metodo comune che restituisce l'IQueryable che potrebbe essere chiamato da il tuo codice o dal controller?

UPDATE: Sulla base di ulteriori informazioni nella domanda iniziale:

Se hai ODataQueryOptions definiti in un metodo di controllo, che vi permetterà di analizzare la query odata ben formato che chiama questo metodo. Ho usato questo quando ho avuto bisogno di tradurre parti di una query odata perché avevo bisogno di interrogare più origini dati per restituire il risultato finale.

Sembra che tu voglia qualcosa che tenga parametri e opzioni non-odata. Per questo, probabilmente avete bisogno di guardare azioni personalizzate e o funzioni (se si è appena la restituzione dei dati, probabilmente una funzione):

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

UPDATE # 2: e dopo aver letto più dettagliata, credo Ho mancato il tuo punto: non ho la risposta, ma ci giocherò. Non puoi semplicemente riformare l'URL stesso (invece di istanziare le opzioni di query?

AGGIORNAMENTO # 3: Penso che avrete difficoltà a indurlo a pensare che stia ottenendo una richiesta di odata ... che in realtà non è una richiesta di odata. Torna la seconda opzione citata nella mia risposta originale - perché non un metodo comune che è possibile utilizzare e il controller odata può usare - qualcosa di simile:

// 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); 
Problemi correlati