http://blogs.clariusconsulting.net/kzu

Daniel Cazzulino's Blog

Go Back to
kzu′s Latest post

Querying WCF endpoints using Web API

In previous versions of the Web API, you could query your REST endpoints that exposed an IQueryable<T> server-side, kinda “Linq to WCF” as @gblock said. This was immensely useful and an important driver (among others) for me to move away from Astoria ADO.NET Data Services. That functionality is gone now (vote to get it back!).

So I was wondering how to bring it back. Would I need to refactor the monstrous (as in big, not ugly) OData client source to reuse just the Uri query translator? This started to look like a daunting task.

Fortunately, after a few back & forth and spelunking in Reflector and the source code, I figured out a way to essentially reuse the entire query translator from the OData services client (built-in .NET 4.0 in the System.Data.Services.Client namespace) and layer it on top of the HttpClient. Awesomeness ensued Smile. Here’s a test from the NETFx NuGet that shows how it works:

[Fact]
public void WhenQuerying_ThenGetsResponse()
{
    var config = HttpHostConfiguration.Create();
    config.Configuration.OperationHandlerFactory.Formatters.Insert(0, new JsonNetMediaTypeFormatter());

    using (var ws = new HttpWebService<TestService>("http://localhost:20000", "products", config))
    {
        var client = new HttpClient("http://localhost:20000");
        client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("text/json"));

        // THIS IS THE DEAL!
        var response = client.Query<Product>("products", x => x.Id <= 2);

        Assert.True(response.IsSuccessStatusCode);

        var products = new JsonSerializer().Deserialize<List<Product>>(new JsonTextReader(new StreamReader(response.Content.ContentReadStream)));

        Assert.Equal(2, products.Count);
        Assert.True(products.All(x => x.Id <= 2));
    }
}

And it even works for sub-properties of the main resource:

var response = client.Query<Product>("products", x => x.Owner.Name == "kzu");

Assert.True(response.IsSuccessStatusCode);

var products = new JsonSerializer().Deserialize<List<Product>>(new JsonTextReader(new StreamReader(response.Content.ContentReadStream)));

Assert.Equal(2, products.Count);
Assert.True(products.All(x => x.Owner.Name == "kzu"));

Yay!

Note that this is a low-level API that follows HttpClient approach: it knows nothing about deserializing the payloads into entities or supported content types, etc. That’s another nuget that’s coming, the HttpEntityClient Smile. Stay tunned.

Enjoy this one by searching for HttpClient (or HttpClientQuery) in the Library Reference dialog:

image

Comments

2 Comments

  1. Thank you for this great information. I wonder what is everyone else using cause this is the only approach I found so far throughout the whole internet. Hope they are not going with the add service reference and the generated code…. Been there, done that with RIA and don’t want to get back.

  2. [...] best thing we found so distant is netFX HttpEntityClient. Though, it looks graceful good, it sounds uncanny that we found zero allied from [...]