Подтвердить что ты не робот

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

Я обычно пишу все части кода на С#, а при написании протоколов, которые сериализованы, я использую 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/сериализации и для детализации сериализации, как описано выше, так что я не нарушаю сериализацию только потому, что другой компьютер еще не обновил свою версию?

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

http://json.codeplex.com/

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

Представьте, что у вас есть объект в ранние дни.

public class Customer
{ 
    public string Name;

    public string LastName;
}

После сериализации он будет выглядеть следующим образом:

{Имя: "John", LastName: "Doe" }

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

public class Customer
{ 
    public string Name;

    public string LastName;

    public int Age;
}

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

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

Итак, давайте скажем: у вас есть класс Customer v1 serialized:

{ 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;
}

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

Ответ 4

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

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

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

В веб-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) данные должны быть самоописательными, другими словами, имена полей всегда должны храниться вместе с данными; вы не должны полагаться на конкретные данные, доступные на определенных позициях.