2016-03-25 3 views
2

Я ищу способ сделать десериализацию от Json, чтобы быть зависимой от версии, используя данные внутри самого Json. Я ориентируюсь на использование ServiceStack.Text.JsonDeserializer, но могу переключиться на другую библиотеку.Версия зависимая Json deserialization

Например, я хотел бы определить данные в формате JSON для v1.0 быть:

{ 
    version: "1.0" 
    condition: "A < B" 
} 

, а затем, в следующей версии данных (скажем, 2.0) будет:

{ 
    version: "2.0" 
    condition: ["A < B", "B = C", "B < 1"] 
} 

В конце я хочу иметь возможность проверить версию данных, чтобы знать, как правильно десериализовать JSON.

UPDATE:

Похоже, что нет какой-либо вид неявной поддержки версий зависит от формата JSON (де) сериализации в известных продуктах.

Правильное решение состоит в том, чтобы разделить задачу на (де) сериализации только части версии, а затем использовать неявные (де) сериализации для правильного типа (ов).

Благодарность всем, кто поделился знаниями и мыслями по проблеме.

+0

Пожалуйста, дайте небольшой пример вашего намерения –

+0

Существует только одна версия JSON. Что именно ты имеешь ввиду? – RvdK

+0

Вы имеете в виду, что у вас есть ключ «Версия: 1.x» поверх вашего JSON? – PTwr

ответ

-1

Посмотрите на

System.Web.Script.Serialization.JavaScriptSerializer 

Образец

var ser = new JavaScriptSerializer(); 
var result = (IReadOnlyDictionary<string, object>)ser.DeserializeObject(json); 

if(result["version"] == "1.0") 
{ 
    // You expect a string for result["condition"] 
} 
else 
{ 
    // You expect an IEnumerable<string> for result["condition"] 
} 
+0

Учитывая пример, который я добавил к вопросу, как этот класс поможет? –

+0

вопрос касался обработки версий (например, разных схем для одного и того же типа) – jgauffin

+0

Вы можете управлять различными версиями с помощью метода DeserializeObject (string). Я отправлю пример. – synapse

0

Вы можете использовать NewtonSoft.Json NuGET package.

Это своего рода стандарт в сообществе .NET. Кроме того, часто упоминается как Json.NET

Вы можете использовать его как это (example с официального сайта):

Product product = new Product(); 

product.Name = "Apple"; 
product.ExpiryDate = new DateTime(2008, 12, 28); 
product.Price = 3.99M; 
product.Sizes = new string[] { "Small", "Medium", "Large" }; 

string output = JsonConvert.SerializeObject(product); 
//{ 
// "Name": "Apple", 
// "ExpiryDate": "2008-12-28T00:00:00", 
// "Price": 3.99, 
// "Sizes": [ 
// "Small", 
// "Medium", 
// "Large" 
// ] 
//} 

Product deserializedProduct = JsonConvert.DeserializeObject<Product>(output); 
+0

Учитывая пример, который я добавил к вопросу, как я могу изменить код для обработки разные версии? –

+0

@LeoY С тех пор как вы перефразировали свой вопрос, мой ответ вышел из строя. Я думаю, что способ сериализации не имеет значения, так как вы реализуете свое управление версиями, что имеет значение в этом случае. –

+0

Я искал какую-то неявную поддержку. Кажется, в этом нет никого, и, вероятно, сериализатор NewtonSoft наиболее удобен для выполнения пользовательской реализации, так как «ServiceStack.Text.JsonSerializer» слишком ориентирован на DTO. –

3

Что вы можете сделать, это либо следующее:

  • Создать базу класс для объектов данных, которые вы хотите десериализовать, которые содержат поле version и ничего больше.
  • Сделать классы данных для разных версий производными классами этого базового класса.
  • Когда вы десериализуете свой объект данных, сначала десериализуйте его как экземпляр вашего базового класса, так что теперь у вас есть объект POCO, который содержит номер версии. Вы можете использовать это, чтобы решить, какие из ваших производных классов данных, которые следует использовать для десериализации данных (в простейшем случае, вы можете сделать переключатель/случай и обрабатывать каждую версию по отдельности)

Пример (с использованием System.Web.Script.Serialization.JavaScriptSerializer) :

class BaseClass 
{ 
    public int version { get; set; } 
} 

class FirstVersion: BaseClass 
{ 
    public string condition { get; set; } 
} 

class SecondVersion: BaseClass 
{ 
    public IEnumerable<string> condition { get; set; } 
} 

public void Deserialize (string jsonString) 
{ 
    JavaScriptSerializer serializer = new JavaScriptSerializer(); 
    BaseClass myData = serializer.Deserialize<BaseClass>(jsonString); 

    switch (myData.version) 
    { 
     case 1: 
      FirstVersion firstVersion = serializer.Deserialize<FirstVersion>(jsonString); 
      // ... 
      break; 
     case 2: 
      SecondVersion secondVersion = serializer.Deserialize<SecondVersion>(jsonString); 
      // ... 
      break; 
    } 
} 

Как вы можете видеть, этот код десериализует данные дважды - что может быть проблемой для вас, если вы работаете с большими структурами данных. Если вы хотите избежать этого любой ценой, вам либо придется отказаться от статической типизации, либо изменить модель данных вашего приложения.

А вот как это выглядит с dynamic:

public void Deserialize (string jsonString) 
{ 
    JavaScriptSerializer serializer = new JavaScriptSerializer(); 
    dynamic myData = serializer.Deserialize<object>(jsonString); 

    if (myData ["version"] == 1) { 
     ... 
    } 
} 

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

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

В Java вы можете использовать библиотеку GSON от Google, так как она имеет built-in support for versioning. Я не изучал его, но это open source, и если это действительно важно для вас, я думаю, вы можете переносить реализацию на другой язык.

+0

Спасибо. Можете ли вы уточнить, как я могу управлять производным производным классом из кода базового класса, как часть десериализации. Поскольку экземпляр класса уже создан, я не могу его воссоздать и заменить. Кажется неудобным иметь оболочку, которая обрабатывает управление версиями и добавляет к ней членов разных типов или создает на лету внутренний член, который хранит фактические данные. Я посмотрю на JavaScriptConverter. –

+0

Это неудобно, но, к сожалению, нет универсального решения этой проблемы (о которой я знаю). Я обновил свой ответ несколькими рекомендациями, которые могут помочь вам. –

1

Я предлагаю вам использовать json.net, это позволяет вам добавлять свои настраиваемые типы конвертирования, которые могут использоваться для управления версиями.

Проблема заключается не в сериализации, поскольку она всегда будет использовать текущую схему. Проблема заключается в том, что клиент использует версию другого типа, которая получает сервер, который получает объект.

Что вам нужно сделать, это проверить версию программно в конвертере типов и преобразовать значение самостоятельно (в этом случае преобразовать строку в массив).

Документация: http://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm

+0

Ваше утверждение не совсем корректно. Это относится к случаю, когда клиент отправляет для современной версии, чем сервер поддерживает. В противном случае сервер может поддерживать предыдущие форматы. Я бы предпочел использовать стандартные средства C# для сериализации, такие как интерфейс ISERializable. –