27
votes

I am trying to use the Northwind OData service:

http://services.odata.org/V3/OData/OData.svc/Products?$format=json

and deserialize it to a collection of products:

    using (var client = new HttpClient())
    {
        HttpResponseMessage response = await client.GetAsync(new Uri(url));
        ObservableCollection<Product> products = await response.Content.ReadAsAsync<ObservableCollection<Product>>();
    }

But the serializer doesn't seem to like the odata.metadata part and the fact that there are 2 odata.type records there (not sure what they are).

Is there an easy way to do this?

5

5 Answers

41
votes

Using Json.Net

using (var client = new HttpClient())
{
    var json = await client.GetStringAsync("http://services.odata.org/V3/OData/OData.svc/Products?$format=json");
    var odata = JsonConvert.DeserializeObject<OData>(json);
}

public class Value
{
    [JsonProperty("odata.type")]
    public string Type { set; get; }
    public int ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public DateTime ReleaseDate { get; set; }
    public DateTime? DiscontinuedDate { get; set; }
    public int Rating { get; set; }
    public double Price { get; set; }
}

public class OData
{
    [JsonProperty("odata.metadata")]
    public string Metadata { get; set; }
    public List<Value> Value { get; set; }
}
29
votes

Define a class for the response from odata (Its a generic definition so you can use this with any type):

internal class ODataResponse<T>
 {
    public List<T> Value { get; set; }
 }

Deserialize like this:

using (var client = new HttpClient())
 {
     HttpResponseMessage response = await client.GetAsync(new Uri(url));
     var json = await response.Content.ReadAsStringAsync();
     var result = JsonConvert.DeserializeObject<ODataResponse<Product>>(json);
     var products = result.Value;
 }
13
votes

If you are using Visual Studio there is a fantastic CLR Class Generation feature built in.

  1. Copy an OData payload into your clipboard
  2. In Visual Studio select the menu option Edit --> Paste Special --> Paste JSON as Object classes

You can then use Json.NET to deserialize into these classes (as described in L.B's answer).

5
votes

There are .NET client for directly consuming OData services. For V3 odata service, you can try with Simple.OData.Client , ODataLib for OData v1-3. For V3 OData service, you can try with OData Client Code Generator. Other libraries for OData client, you can refer to http://www.odata.org/libraries/ .

4
votes

Another potential way to manage the deserialisation problem caused by the odata.metadata part is to request that the odata response doesn't contain the metadata. This can be done with a default request header in the http client:

client.DefaultRequestHeaders.Add("Accept", "application/json;odata.metadata=none");

Which allows the object to then be deserialised with ReadAsAsync:

var products = response.Content.ReadAsAsync<Dictionary<string, ObservableCollection<Product>>>().Result["value"]

This seems much cleaner than having to write another class to handle the response. Using .Result might not be the best way as the code isn't then asynchronous, but it wasn't important in my application and made the code occupy fewer lines.