Десериализация массива JSON в ObservableCollection


Я использую RestSharp для связи с удаленным сервером. Я получаю сериализованную строку JSON, которую я могу десериализовать в объект c#. Я также могу десериализовать массивы json в список. Однако я хочу, чтобы эти объекты использовались в привязках WPF, поэтому мне нужно будет поместить их в ObservableCollection для удобства. Однако, если я попытаюсь изменить свойство из списка в ObservableCollection (или IList, или ICollection, или Collection), я получу исключение на десериализация.

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

Базовый код на самом деле не является особенным, но здесь он так или иначе:

private ObservableCollection<StationDto> stations;

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

Я понимаю, что интерфейсы не будут работать, потому что Json.net нужен конкретный класс для сериализации.

Я сделал изрядное количество гуглов, но я не видел решения для этого. Существует ли шаблон, который обычно используется для прокси-серверов ручной работы, используемых для служб json/rest?
1 3

1 ответ:

Глядя на исходный код для RestSharp , кажется, что он использует свой собственный внутренний десериализатор JSON (называемый SimpleJson), в отличие от использования Json.Net документацияRestSharp по десериализации подтверждает, что десериализатор поддерживает только типы коллекций List<T> и Dictionary<T1,T2>. Json.Net , С другой стороны, гораздо более надежен и может обрабатывать десериализацию в наблюдаемые коллекции. Я попробовал его с кодом в конце этого поста и не увидел возможные проблемы. Имея это в виду, я бы рекомендовал добавить Json.Net к вашему решению и использовать его для десериализации результатов вызовов REST API вместо того, чтобы полагаться на внутренний десериализатор RestSharp. Есть несколько способов сделать это:

  1. Вместо вызова Execute<T>() на RestClient, Вы можете вызвать Execute() вместо этого. Execute() возвращает IRestResponse, который имеет свойство Content, которое будет содержать необработанную строку JSON, возвращенную из запроса. Вы можете взять эту строку и передать ее Json.Net метод s JsonConvert.DeserializeObject<T>().

  2. Создайте класс, реализующий интерфейс RestSharp IDeserializer. Сделайте этот класс просто передать Json.Net чтобы выполнить фактическую работу по десериализации JSON. Затем вы можете попросить RestSharp использовать этот пользовательский десериализатор вместо своего собственного, вызвав AddHandler() в классе RestClient. Согласно документации, обработчики, добавленные таким образом, заменят существующие для того же типа контента. Затем вы можете продолжать использовать RestClient таким же образом вы уже есть, но теперь он должен работать с ObservableCollections.

Вот код, который я использовал для проверки того, что Json.Net десериализуется в 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)
    {
    }
}