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"), нулев, празен списък или списък с една или повече стойности. Важно е клиентите да разберат как да се държат, особено в недефинираните / нулеви / празни случаи.

Бих препоръчал също да прочетете каксемантична версиявърши работа. Ако въведете семантична схема за управление на версиите на номерата на версиите си, тогава съвместими с обратно промени могат да бъдат направени на малка граница на версията, докато пробивните промени могат да бъдат направени на основната граница на версията (както клиентите, така и сървърите трябва да се споразумеят за една и съща основна версия ). Въпреки че това не е свойство на самия JSON, това е полезно за комуникация на видовете промени, които клиентът трябва да очаква, когато се промени версията.

източник
Translate

Java на Googlegson библиотекаима отлична поддръжка на версии за json. Може да се окаже много удобно, ако мислите да отидете на Java.

Има лесен и лесен уроктук.

източник
Translate

Не използвайте DataContractJsonSerializer, както се казва в името, обектите, които се обработват чрез този клас, ще трябва:

а) Бъдете маркирани с атрибути [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 към този нов клас, няма да има грешка. Работата е там, че новите ви полета ще бъдат настроени по подразбиране. В този пример: "Възраст" ще бъде зададен на нула.

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

Така че, нека кажем: Имате сериализиран клиент на вашия клас v1:

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

Ако искате да десериализирате в екземпляр на клиент 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