serialization - Каков наилучший способ управления версиями с использованием протокола JSON?

Translate

Обычно я пишу все части кода на C #, а при написании сериализованных протоколов я использую FastSerializer, который сериализует / десериализует классы быстро и эффективно. Кроме того, очень легко использовать и довольно просто выполнять «управление версиями», то есть обрабатывать различные версии сериализации. То, что я обычно использую, выглядит так:

public override void DeserializeOwnedData(SerializationReader reader, object context)
{
    base.DeserializeOwnedData(reader, context);
    byte serializeVersion = reader.ReadByte(); // used to keep what version we are using

    this.CustomerNumber = reader.ReadString();
    this.HomeAddress = reader.ReadString();
    this.ZipCode = reader.ReadString();
    this.HomeCity = reader.ReadString();
    if (serializeVersion > 0)
        this.HomeAddressObj = reader.ReadUInt32();
    if (serializeVersion > 1)
        this.County = reader.ReadString();
    if (serializeVersion > 2)
        this.Muni = reader.ReadString();
    if (serializeVersion > 3)
        this._AvailableCustomers = reader.ReadList<uint>();
}

и

public override void SerializeOwnedData(SerializationWriter writer, object context)
{            
    base.SerializeOwnedData(writer, context);
    byte serializeVersion = 4; 
    writer.Write(serializeVersion);


    writer.Write(CustomerNumber);
    writer.Write(PopulationRegistryNumber);            
    writer.Write(HomeAddress);
    writer.Write(ZipCode);
    writer.Write(HomeCity);
    if (CustomerCards == null)
        CustomerCards = new List<uint>();            
    writer.Write(CustomerCards);
    writer.Write(HomeAddressObj);

    writer.Write(County);

    // v 2
    writer.Write(Muni);

    // v 4
    if (_AvailableCustomers == null)
        _AvailableCustomers = new List<uint>();
    writer.Write(_AvailableCustomers);
}

Так что легко добавить что-то новое или полностью изменить сериализацию, если кто-то захочет.

Однако теперь я хочу использовать JSON по причинам, которые здесь не актуальны =) В настоящее время я используюDataContractJsonSerializerи теперь я ищу способ иметь такую же гибкость, как при использовании FastSerializer выше.

Итак, вопрос: как лучше всего создать протокол / сериализацию JSON и иметь возможность детализировать сериализацию, как указано выше, чтобы я не нарушал сериализацию только потому, что другая машина еще не обновила свою версию?

This question and all comments follow the "Attribution Required."

Все ответы

Translate

Ключ к управлению версиями JSON - всегда добавлять новые свойства и никогда не удалять или переименовывать существующие свойства. Это похоже накак буферы протокола обрабатывают управление версиями.

Например, если вы начали со следующего JSON:

{
  "version": "1.0",
  "foo": true
}

И вы хотите переименовать свойство «foo» в «bar», а не просто переименовывать его. Вместо этого добавьте новое свойство:

{
  "version": "1.1",
  "foo": true,
  "bar": true
}

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

Также важно четко определить ваши «крайние» случаи для ваших клиентов. Предположим, у вас есть свойство массива под названием «fooList». Свойство "fooList" может принимать следующие возможные значения: не существует / не определено (свойство физически не присутствует в объекте JSON или существует и имеет значение "undefined"), null, пустой список или список с одно или несколько значений. Важно, чтобы клиенты понимали, как себя вести, особенно в случаях undefined / null / empty.

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

Источник
Translate

Google на основе Javaбиблиотека gsonимеет отличную поддержку версий для json. Это может оказаться очень полезным, если вы думаете о java.

Есть хороший и простой учебникВот.

Источник
Translate

Не используйте DataContractJsonSerializer, как следует из названия, объекты, которые обрабатываются этим классом, должны будут:

a) быть отмеченными атрибутами [DataContract] и [DataMember].

б) Строго соблюдайте определенный «Контракт», то есть ни меньше, ни больше, что он определен. Любой лишний или отсутствующий [DataMember] вызовет десериализацию с выдачей исключения.

Если вы хотите быть достаточно гибкими, используйте JavaScriptSerializer, если вы хотите выбрать дешевый вариант ... или используйте эту библиотеку:

http://json.codeplex.com/

Это даст вам достаточный контроль над сериализацией JSON.

Представьте, что у вас есть объект в первые дни его существования.

public class Customer
{ 
    public string Name;

    public string LastName;
}

После сериализации это будет выглядеть так:

{Имя: "Джон", Фамилия: "Лань"}

Если вы измените определение объекта, чтобы добавить / удалить поля. Десериализация будет происходить плавно, если вы используете, например, JavaScriptSerializer.

public class Customer
{ 
    public string Name;

    public string LastName;

    public int Age;
}

Если вы попытаетесь десериализовать последний json в этот новый класс, ошибки не будет. Дело в том, что для ваших новых полей будут установлены значения по умолчанию. В этом примере: «Возраст» будет установлен на ноль.

Вы можете включить в свои собственные соглашения поле, присутствующее во всех ваших объектах, которое содержит номер версии. В этом случае вы можете отличить пустое поле от несоответствия версии.

Итак, скажем: у вас сериализован ваш класс Customer v1:

{ Version: 1, LastName: "Doe", Name: "John" }

Если вы хотите выполнить десериализацию в экземпляр Customer v2, у вас будет:

{ Version: 1, LastName: "Doe", Name: "John", Age: 0}

Вы можете каким-то образом определить, какие поля в вашем объекте надежны, а какие нет. В этом случае вы знаете, что ваш экземпляр объекта v2 поступает из экземпляра объекта v1, поэтому полю Age не следует доверять.

Я имею в виду, что вы также должны использовать настраиваемый атрибут, например «MinVersion», и пометить каждое поле минимальным поддерживаемым номером версии, чтобы получить что-то вроде этого:

public class Customer
{ 
    [MinVersion(1)]
    public int Version;

    [MinVersion(1)]
    public string Name;

    [MinVersion(1)]
    public string LastName;

    [MinVersion(2)]
    public int Age;
}

Позже вы сможете получить доступ к этим метаданным и делать с ними все, что вам нужно.

Источник
Translate

Неважно, какой протокол сериализации вы используете, методы для версии API обычно одинаковы.

Обычно вам нужно:

  1. способ для потребителя сообщить производителю версию API, которую он принимает (хотя это не всегда возможно)
  2. способ для производителя встроить информацию о версиях в сериализованные данные
  3. стратегия обратной совместимости для обработки неизвестных полей

В веб-API обычно версия API, которую принимает потребитель, встроена в заголовок Accept (например,Accept: application/vnd.myapp-v1+json application/vnd.myapp-v2+jsonозначает, что потребитель может обрабатывать либо версию 1, либо версию 2 вашего API) или реже в URL-адресе (например,https://api.twitter.com/1/statuses/user_timeline.json). Обычно это используется для основных версий (т.е. изменений, несовместимых с предыдущими версиями). Если сервер и клиент не имеют совпадающего заголовка Accept, то связь не выполняется (или продолжается в режиме максимальных усилий или откат к базовому протоколу по умолчанию, в зависимости от характера приложения).

Затем производитель генерирует сериализованные данные в одной из запрошенных версий, а затем вставляет эту информацию о версии в сериализованные данные (например, как поле с именемversion). Потребитель должен использовать информацию о версии, встроенную в данные, чтобы определить, как анализировать сериализованные данные. Информация о версии в данных также должна содержать второстепенную версию (т.е. для изменений с обратной совместимостью), как правило, потребители должны иметь возможность игнорировать информацию о дополнительной версии и по-прежнему обрабатывать данные правильно, хотя понимание дополнительной версии может позволить клиенту сделать дополнительные предположения о как следует обрабатывать данные.

Обычная стратегия обработки неизвестных полей аналогична синтаксическому анализу HTML и CSS. Когда потребитель видит неизвестное поле, он должен его игнорировать, а когда в данных отсутствует поле, которое ожидает клиент, он должен использовать значение по умолчанию; в зависимости от характера связи вы также можете указать некоторые поля, которые являются обязательными (т.е. отсутствие полей считается фатальной ошибкой). Поля, добавленные в дополнительных версиях, всегда должны быть необязательными; младшая версия может добавлять необязательные поля или изменять семантику полей, если она обратно совместима, в то время как основная версия может удалять поля или добавлять обязательные поля или изменять семантику полей обратно несовместимым образом.

В расширяемом формате сериализации (таком как JSON или XML) данные должны быть информативными, другими словами, имена полей всегда должны храниться вместе с данными; вам не следует полагаться на конкретные данные, доступные по конкретным позициям.

Источник
Leave a Reply
You must be logged in to post a answer.
Об авторе
Ted