Десериализовать объекты json и преобразовать внутренние объекты в строковое значение?

У меня есть веб-сервис, возвращающий данные json. У меня нет контроля над сгенерированным json на стороне сервера.

Я десериализую json следующим образом:

JsonConvert.DeserializeObject<OuterObject>(jsonString);

Проблема в том, что есть встроенные внутренние объекты (с большим количеством вложенных внутренних объектов). Я не заинтересован в моделировании их в моем приложении.

Json-данные выглядят так:

{ 
    id : "xyz",
    name : "Some Object",
    properties : {
        prop_1 : "foo",
        prop_2 : "bar"
    },
    inner_object : {
        id : "abc$1",
        name : "Inner Object Name",
        ....
        // a whole lot of stuff here
        // with more embedded objects
        ....
    }
}

Я хотел бы смоделировать внешний объект как простой POCO, где на внутренний объект ссылается только идентификатор (String), а не ссылка на объект.

public class Outer
{
    public String Id { get; internal set; }
    public String Name { get; internal set; }
    public Dictionary<String,String> Properties { get; internal set; }

    // Just keep the InnerObject Id, no real reference to an instance
    public String InnerObjectId { get; set; }
}

Я думаю, я мог бы написать версию JsonOuterObject со ссылкой на реальный объект для JsonInnerObject и создать оттуда мой реальный OuterObject, отбрасывая впоследствии другие объекты ... но это слишком хромо. (Я не хочу видеть свое имя рядом с таким коммитом)

Итак, сейчас я играю с Json.NET IContractResolver (переопределяя DefaultContractResolver), но похоже, что мне предстоит долгая поездка.

Мне не хватает какой-то очевидной функции Json.NET, которая позаботится об этом здесь?

Или, может быть, какие-то указатели, какие методы IContractResolver здесь интересны?

EDIT: POJO в .NET — это POCO.


person toong    schedule 19.09.2011    source источник
comment
если у вас есть какой-либо контроль над отправляемыми объектами, вы можете просто удалить эти нежелательные атрибуты...   -  person J. Ed    schedule 19.09.2011
comment
Ну, как я уже сказал: я не :-)   -  person toong    schedule 20.09.2011


Ответы (2)


Одним из подходов может быть использование Newtonsoft.Json.Linq и динамических типов, поскольку вы, по сути, пытаетесь (или вынуждены) изменить правила безопасности типов.

    public class Outer
    {            
        [JsonProperty(PropertyName = "id")]
        public String Id { get; internal set; }
        [JsonProperty(PropertyName = "name")]
        public String Name { get; internal set; }
        [JsonProperty(PropertyName = "properties")]
        public Dictionary<String, String> Properties { get; internal set; }
        [JsonProperty(PropertyName = "inner_object")]
        public dynamic InnerObjectId { get; set; }
    }

    public void InnerObjectAsDynamic()
    {
        const string json = @"{""id"":""xyz"",""name"":""Some Object"",""properties"":{""prop_1"":""foo"",""prop_2"":""bar""},""inner_object"":{""id"":""abc$1"",""name"":""Inner Object Name""}}";
        var outer = JsonConvert.DeserializeObject<Outer>(json);
        var innerObjectJson = outer.InnerObjectId.ToString();
        Console.WriteLine(innerObjectJson);
        //{
        //  "id": "abc$1",
        //  "name": "Inner Object Name"
        //}
    }

В качестве альтернативы вы можете определить Outer как:

    public class Outer
    {
        [JsonProperty(PropertyName = "id")]
        public String Id { get; internal set; }
        [JsonProperty(PropertyName = "name")]
        public String Name { get; internal set; }
        [JsonProperty(PropertyName = "properties")]
        public Dictionary<String, String> Properties { get; internal set; }
        [JsonProperty(PropertyName = "inner_object")]
        public Newtonsoft.Json.Linq.JObject InnerObjectId { get; set; }
    }

Это немного чище для меня. Удачи.

person Frank    schedule 20.09.2011

Создание пользовательского JsonConverter для внешнего типа обеспечивает большую гибкость при десериализации объектов.

Это значительно больше работы, но это может стоить усилий. Особенно, если у вас нет контроля над возвращаемым объектом JSON, и вы хотели бы по-другому смоделировать возвращаемые данные в своем клиентском приложении.

Мясо реализации JsonConverter переопределяет метод ReadJson.

public override object ReadJson(JsonReader reader,
                                Type objectType,
                                object existingValue,
                                JsonSerializer serializer)

JsonReader — это токенизированный поток ваших данных. Реализация может быть такой:

public override object ReadJson(JsonReader reader,
                                Type objectType,
                                object existingValue,
                                JsonSerializer serializer)
{
    var outer = new Outer()

    while (reader.TokenType != JsonToken.EndObject)
    {
        if (reader.TokenType == JsonToken.PropertyName)
        {
            var propertyName = reader.Value.ToString();
            reader.Read();

            switch (propertyName)
            {
                case "id":
                    outer.Id = serializer.Deserialize<String>(reader);
                    break;
                case "id":
                    outer.Properties = serializer.Deserialize<Dictionary<String,String>>(reader);
                    break;
                case "inner_object"
                    var inner = serializer.Deserialize<Inner>(reader);
                    outer.InnerObjectId = inner.Id;
                    break;
                [...more cases...]
                default:
                    serializer.Deserialize<object>(reader);
                    break;
                }
                reader.Read(); // consume tokens in reader
            }
        } else {
            // throw exception ?
        }
    }

    return outer;
}

Вы можете аннотировать свой внешний объект с помощью JsonConverterAttribute или передать длинный преобразователь в (перегруженный) метод Deserialize (String json, params JsonConverter [] converters) класса JsonConverter

person toong    schedule 21.09.2011