简体   繁体   中英

Deserializing a JSON array to a ObservableCollection

I am using RestSharp to communicate with a remote server. I receive a JSON serialized string, which i am able to deserialize into ac# object. I also am able to deserialize json arrays to List. However, i want those objects to be used in WPF bindings so i would need to put them in an ObservableCollection for convenience. However, if i try to change the property from List to ObservableCollection (or IList, or ICollection, or Collection) i get an exception on deserialization.

Unable to cast object of type 'RestSharp.JsonArray' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]

The underlying code is really not special, but here it is anyway:

private ObservableCollection<StationDto> stations;

[JsonProperty(PropertyName = "stations")]
public ObservableCollection<StationDto> Stations
{
    get { return this.stations; }
    set
    {
        this.stations = value;
        RaisePropertyChanged(() => Stations);
    }
}

I understand that Interfaces won't work cause Json.net needs a concrete class to serialize to.

I have done a fair amount of googling but i have not seen a solution for this. Is there a pattern that is commonly used for hand-crafted proxies used for json/rest services?

Looking at the source code for RestSharp , it appears that it uses its own internal JSON deserializer (called SimpleJson), as opposed to using Json.Net. The RestSharp documentation on deserialization confirms that the deserializer only supports List<T> and Dictionary<T1,T2> collection types. Json.Net , on the other hand, is much more robust, and can handle deserializing into ObservableCollections. I tried it with the code at the end of this post and did not see any problems. With this in mind, I would recommend adding Json.Net to your solution and using that to deserialize the results of your REST API calls instead of relying on RestSharp's internal deserializer. There are a couple of ways to do this:

  1. Instead of calling Execute<T>() on the RestClient , you can call Execute() instead. Execute() returns an IRestResponse which has a Content property that will contain the raw JSON string returned from the request. You can take this string and pass it to Json.Net's JsonConvert.DeserializeObject<T>() method.

  2. Create a class which implements RestSharp's IDeserializer interface. Make this class simply hand off to Json.Net to do the actual work of deserializing the JSON. You can then tell RestSharp to use this custom deserializer instead of its own by calling AddHandler() on the RestClient class. According to the documentation, handlers you add in this way will replace existing ones for the same content type. Then, you can continue to use the RestClient in the same way you already are, except it should now work with ObservableCollections .

Here is the code I used to test that the Json.Net will deserialize into an ObservableCollection :

class Program
{
    static void Main(string[] args)
    {
        string json = @"{""stations"":[{""Name"":""WXRT""},{""Name"":""WGN""}]}";

        Foo foo = JsonConvert.DeserializeObject<Foo>(json);

        foreach (StationDto dto in foo.Stations)
        {
            Console.WriteLine(dto.Name);
        }
    }
}

class StationDto
{
    public string Name { get; set; }
}

class Foo
{
    private ObservableCollection<StationDto> stations;

    [JsonProperty(PropertyName = "stations")]
    public ObservableCollection<StationDto> Stations
    {
        get { return this.stations; }
        set 
        { 
            this.stations = value;
            RaisePropertyChanged(() => Stations);
        }
    }

    private void RaisePropertyChanged(Func<ObservableCollection<StationDto>> coll)
    {
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM