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

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

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?


person Community    schedule 11.05.2013    source источник


Ответы (1)


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

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

  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)
    {
    }
}
person Brian Rogers    schedule 13.05.2013
comment
Спасибо за ваше предложение, но я уже использовал Json.NET вместо встроенного. Возможно, мне придется вызвать JsonConverter самому, хотя я надеялся, что будет достаточно просто установить сериализатор и десериализатор на сериализатор Json.NET, к сожалению, это не так. - person ; 14.05.2013
comment
Хм, если вы используете сериализатор Json.Net, как вы получаете сообщение об ошибке Unable to cast object of type RestSharp.JsonArray, которое вы указали в своем вопросе? Json.Net не имеет типа JsonArray; он использует JArray. Сериализатор SimpleJson RestSharp использует JsonArray. Поэтому, если вы получаете эту ошибку, это может указывать на то, что RestSharp все еще использует свой внутренний сериализатор, а не Json.Net. Не могли бы вы опубликовать код, который вы используете для настройки сериализатора? - person Brian Rogers; 14.05.2013
comment
Я нашел проблему. Я забыл добавить обработчики с помощью AddHandler, как вы упомянули в своем ответе. Мой десериализатор никогда не вызывался. - person ; 15.05.2013
comment
Ах, да, это бы многое объяснило. Рад, что вы смогли найти проблему. - person Brian Rogers; 15.05.2013
comment
Мы добавили в наш класс список привязок, и вдруг выскочила эта ошибка. Не знал, что RestSahrp использует собственную версию сериализатора json. Вариант 1 спас меня, спасибо!!! - person Richard S.; 22.07.2016