serialization - Qual è il modo migliore per gestire il versioning usando il protocollo JSON?

Translate

Normalmente sto scrivendo tutte le parti del codice in C # e durante la scrittura di protocolli serializzati utilizzo FastSerializer che serializza / deserializza le classi in modo rapido ed efficiente. È anche molto facile da usare e abbastanza diretto per eseguire il "controllo delle versioni", cioè per gestire diverse versioni della serializzazione. La cosa che uso normalmente ha questo aspetto:

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>();
}

e

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

Quindi è facile aggiungere nuove cose o cambiare completamente la serializzazione se si sceglie di farlo.

Tuttavia, ora desidero utilizzare JSON per motivi non rilevanti qui =) che sto attualmente utilizzandoDataContractJsonSerializere ora sto cercando un modo per avere la stessa flessibilità che ho usando FastSerializer sopra.

Quindi la domanda è; qual è il modo migliore per creare un protocollo / serializzazione JSON e per poter dettagliare la serializzazione come sopra, in modo da non interrompere la serializzazione solo perché un'altra macchina non ha ancora aggiornato la propria versione?

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

Tutte le risposte

Translate

La chiave per il controllo delle versioni di JSON è aggiungere sempre nuove proprietà e non rimuovere o rinominare mai le proprietà esistenti. Questo è simile acome i buffer di protocollo gestiscono il controllo delle versioni.

Ad esempio, se hai iniziato con il seguente JSON:

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

E vuoi rinominare la proprietà "foo" in "bar", non rinominarla semplicemente. Invece, aggiungi una nuova proprietà:

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

Poiché non rimuovi mai le proprietà, i client basati su versioni precedenti continueranno a funzionare. Lo svantaggio di questo metodo è che il JSON può gonfiarsi nel tempo e devi continuare a mantenere le vecchie proprietà.

È anche importante definire chiaramente i tuoi casi "marginali" per i tuoi clienti. Supponiamo di avere una proprietà array chiamata "fooList". La proprietà "fooList" potrebbe assumere i seguenti possibili valori: non esiste / undefined (la proprietà non è fisicamente presente nell'oggetto JSON, oppure esiste ed è impostata su "undefined"), null, elenco vuoto o un elenco con uno o più valori. È importante che i client capiscano come comportarsi, specialmente nei casi non definiti / nulli / vuoti.

Consiglierei anche di leggere su comecontrollo delle versioni semanticolavori. Se si introduce uno schema di controllo delle versioni semantico nei numeri di versione, è possibile apportare modifiche compatibili con le versioni precedenti su un limite di versione minore, mentre è possibile apportare modifiche importanti al limite di versione principale (sia i client che i server dovrebbero concordare la stessa versione principale ). Sebbene questa non sia una proprietà del JSON stesso, è utile per comunicare i tipi di modifiche che un client dovrebbe aspettarsi quando la versione cambia.

fonte
Translate

Basato su Java di Googlelibreria gsonha un eccellente supporto per il controllo delle versioni per json. Potrebbe rivelarsi molto utile se stai pensando di andare in java.

C'è un tutorial piacevole e facileQui.

fonte
Translate

Non utilizzare DataContractJsonSerializer, come dice il nome, gli oggetti che vengono elaborati tramite questa classe dovranno:

a) Essere contrassegnato con gli attributi [DataContract] e [DataMember].

b) Essere rigorosamente conformi al "Contratto" definito, ovvero niente di meno e niente di più che è definito. Qualsiasi [DataMember] aggiuntivo o mancante farà sì che la deserializzazione generi un'eccezione.

Se vuoi essere abbastanza flessibile, usa JavaScriptSerializer se vuoi optare per l'opzione economica ... o usa questa libreria:

http://json.codeplex.com/

Questo ti darà un controllo sufficiente sulla serializzazione JSON.

Immagina di avere un oggetto nei suoi primi giorni.

public class Customer
{ 
    public string Name;

    public string LastName;
}

Una volta serializzato, sarà simile a questo:

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

Se modifichi la definizione dell'oggetto per aggiungere / rimuovere campi. La deserializzazione avverrà senza problemi se utilizzi, ad esempio, JavaScriptSerializer.

public class Customer
{ 
    public string Name;

    public string LastName;

    public int Age;
}

Se si tenta di de-serializzare l'ultimo json in questa nuova classe, non verrà generato alcun errore. Il fatto è che i tuoi nuovi campi verranno impostati sui valori predefiniti. In questo esempio: "Age" verrà impostato su zero.

Puoi includere, nelle tue convenzioni, un campo presente in tutti i tuoi oggetti, che contiene il numero di versione. In questo caso puoi distinguere tra un campo vuoto o un'incongruenza di versione.

Quindi diciamo: hai serializzato la tua classe Customer v1:

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

Se desideri deserializzare in un'istanza v2 del cliente, avrai:

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

Puoi in qualche modo rilevare quali campi nel tuo oggetto sono in qualche modo affidabili e cosa no. In questo caso sai che la tua istanza di oggetto v2 proviene da un'istanza di oggetto v1, quindi il campo Age non dovrebbe essere considerato attendibile.

Ho in mente che dovresti usare anche un attributo personalizzato, ad esempio "MinVersion", e contrassegnare ogni campo con il numero di versione minimo supportato, in modo da ottenere qualcosa del genere:

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

    [MinVersion(1)]
    public string Name;

    [MinVersion(1)]
    public string LastName;

    [MinVersion(2)]
    public int Age;
}

Successivamente potrai accedere a questi metadati e fare tutto ciò di cui potresti aver bisogno.

fonte
Translate

Non importa quale protocollo di serializzazione usi, le tecniche per la versione delle API sono generalmente le stesse.

Generalmente hai bisogno di:

  1. un modo per il consumatore di comunicare al produttore la versione API che accetta (anche se questo non è sempre possibile)
  2. un modo per il produttore di incorporare le informazioni sul controllo delle versioni nei dati serializzati
  3. una strategia compatibile con le versioni precedenti per gestire campi sconosciuti

In un'API web, generalmente la versione dell'API che il consumatore accetta è incorporata nell'intestazione Accept (esAccept: application/vnd.myapp-v1+json application/vnd.myapp-v2+jsonsignifica che il consumatore può gestire sia la versione 1 che la versione 2 della tua API) o meno comunemente nell'URL (ad eshttps://api.twitter.com/1/statuses/user_timeline.json). Questo è generalmente utilizzato per le versioni principali (cioè modifiche incompatibili con le versioni precedenti). Se il server e il client non hanno un'intestazione Accept corrispondente, la comunicazione non riesce (o procede con il massimo impegno o fallback a un protocollo di base predefinito, a seconda della natura dell'applicazione).

Il produttore quindi genera un dato serializzato in una delle versioni richieste, quindi incorpora queste informazioni sulla versione nei dati serializzati (ad esempio come un campo denominatoversion). Il consumatore dovrebbe utilizzare le informazioni sulla versione incorporate nei dati per determinare come analizzare i dati serializzati. Le informazioni sulla versione nei dati dovrebbero contenere anche una versione secondaria (cioè per modifiche compatibili con le versioni precedenti), in genere i consumatori dovrebbero essere in grado di ignorare le informazioni sulla versione secondaria e comunque elaborare i dati correttamente sebbene la comprensione della versione secondaria possa consentire al cliente di formulare ipotesi aggiuntive su come devono essere elaborati i dati.

Una strategia comune per gestire i campi sconosciuti è simile al modo in cui vengono analizzati HTML e CSS. Quando il consumatore vede un campo sconosciuto, dovrebbe ignorarlo e quando nei dati manca un campo che il cliente si aspetta, dovrebbe usare un valore predefinito; a seconda della natura della comunicazione, potresti anche voler specificare alcuni campi che sono obbligatori (cioè i campi mancanti sono considerati errori fatali). I campi aggiunti nelle versioni secondarie dovrebbero sempre essere campi facoltativi; la versione secondaria può aggiungere campi opzionali o modificare la semantica dei campi purché sia retrocompatibile, mentre la versione principale può eliminare campi o aggiungere campi obbligatori o modificare la semantica dei campi in modo incompatibile all'indietro.

In un formato di serializzazione estensibile (come JSON o XML), i dati dovrebbero essere auto-descrittivi, in altre parole, i nomi dei campi dovrebbero essere sempre memorizzati insieme ai dati; non dovresti fare affidamento sui dati specifici disponibili su posizioni specifiche.

fonte
Leave a Reply
You must be logged in to post a answer.
Circa l'autore
Ted