Search code examples
c#linqodata

Strong-typed Linq to construct OData query options


Assume the following example that demonstrates how to perform read operation using HttpClient:

using (var client = new HttpClient())
{
    client.BaseAddress = webUri;
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    var requestUrl = "/api/products?$filter=(Category eq 'Cars')";

    var response = await client.GetAsync(requestUrl);
    if (response.IsSuccessStatusCode)
    {
       var products = await response.Content.ReadAsAsync<List<Product>>();
    }
}

So far so good, but what about constructing REST endpoint Url from a Linq query?

To summarize, the goal is to utilize strong-typed Linq expression for constructing REST endpoint Url, for example the query:

var products = client.Get<List<Product>>().Where(p => p.Category == "Cars");

will be transformed into:

/api/products?$filter=(Category eq 'Cars')

Are there any .Net library that allows to transform Linq expression into OData query option string?


Solution

  • You can use the WCF Data Service client to build the query for you then parse out the result.

    // url doesn't matter unless you will use data service to execute the call
    var dsContext = new DataServiceContext(new Uri("http://stackoverflow"));
    // need to pass in the controller into CreateQuery - could create an extension method to pluralize the type to not have to pass it in. 
    var query = dsContext.CreateQuery<Product>("/api/products").Where(p => p.Category == "Cars");
    // ToString will output the url
    var uri = new Uri(query.ToString());
    // Grab just the path and query
    var path = new Uri(uri.PathAndQuery, UriKind.RelativeOrAbsolute);
    await client.GetAsync(path); // this will call the api not DataServiceContext
    

    But if you are going to use DataServiceContext then you might just want to use it to execute the query for you instead of using httpclient - this works for OData V1-3 I don't know if it works for V4. The query variable will be an IQueryable and you could just execute it.