Graeme
Graeme

Reputation: 2687

How to deserialize oData JSON?

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?

Upvotes: 33

Views: 45766

Answers (6)

kipras
kipras

Reputation: 89

Another way to handle it is to use JObject Data

 JsonConvert.DeserializeObject<JObject>(response)["value"].ToObject<List<Product>>()

Upvotes: 3

Rand0mChar
Rand0mChar

Reputation: 51

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.

Upvotes: 5

ozanmut
ozanmut

Reputation: 3234

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;
 }

Upvotes: 36

ScottB
ScottB

Reputation: 1363

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).

Upvotes: 15

QianLi
QianLi

Reputation: 1098

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/ .

Upvotes: 5

L.B
L.B

Reputation: 116118

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; }
}

Upvotes: 46

Related Questions