4

I am using RestSharp to communicate with a remote server. I receive a JSON serialized string, which i am able to deserialize into a c# 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?

1 Answers1

7

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)
    {
    }
}
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • Thanks for your suggestion but i was already using Json.NET instead of the built in. I might need to call the JsonConverter myself though i was hoping just setting the Serializer and Deserializer to a Json.NET serializer would suffice, unfortunatly it is not. –  May 14 '13 at 16:12
  • Hmmm, if you are using the Json.Net serializer, how are you getting the "Unable to cast object of type 'RestSharp.JsonArray'" error you posted in your question? Json.Net does not have a `JsonArray` type; it uses `JArray`. RestSharp's SimpleJson serializer uses `JsonArray`. So if you are getting that error, that would seem to indicate that RestSharp is still using its internal serializer and not Json.Net. Would you care to post the code you are using to set up the serializer? – Brian Rogers May 14 '13 at 19:12
  • I found the problem. I forgot to add the Handlers with AddHandler, like you mentioned in your answer. My Deserializer was never called. –  May 15 '13 at 18:28
  • Ah, yes, that would explain things. Glad you were able to find the problem. – Brian Rogers May 15 '13 at 18:39
  • 1
    We added a binding list to our class, and all of a sudden this error popped up. Didn't realize RestSahrp used its own version of a json serializer. Option 1 is what saved me, thanks!!! – Richard S. Jul 22 '16 at 20:43