serialization - Was ist der beste Weg, um die Versionierung mit dem JSON-Protokoll zu handhaben?

Translate

Normalerweise schreibe ich alle Teile des Codes in C # und wenn ich serialisierte Protokolle schreibe, verwende ich FastSerializer, der die Klassen schnell und effizient serialisiert / deserialisiert. Es ist auch sehr einfach zu bedienen und ziemlich einfach, "Versionierung" durchzuführen, dh verschiedene Versionen der Serialisierung zu handhaben. Das, was ich normalerweise benutze, sieht folgendermaßen aus:

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

und

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

So ist es einfach, neue Dinge hinzuzufügen oder die Serialisierung komplett zu ändern, wenn man möchte.

Jetzt möchte ich JSON jedoch aus Gründen verwenden, die hier nicht relevant sind =) Ich verwende es derzeitDataContractJsonSerializerund ich suche jetzt nach einer Möglichkeit, die gleiche Flexibilität zu haben, die ich mit dem oben genannten FastSerializer habe.

Die Frage ist also: Was ist der beste Weg, um ein JSON-Protokoll / eine JSON-Serialisierung zu erstellen und die Serialisierung wie oben detailliert darzustellen, damit ich die Serialisierung nicht unterbreche, nur weil ein anderer Computer seine Version noch nicht aktualisiert hat?

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

Alle Antworten

Translate

Der Schlüssel zur Versionierung von JSON besteht darin, immer neue Eigenschaften hinzuzufügen und vorhandene Eigenschaften niemals zu entfernen oder umzubenennen. Dies ist ähnlich wieWie Protokollpuffer mit der Versionierung umgehen.

Wenn Sie beispielsweise mit dem folgenden JSON begonnen haben:

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

Und Sie möchten die Eigenschaft "foo" in "bar" umbenennen, nicht nur umbenennen. Fügen Sie stattdessen eine neue Eigenschaft hinzu:

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

Da Sie niemals Eigenschaften entfernen, funktionieren Clients, die auf älteren Versionen basieren, weiterhin. Der Nachteil dieser Methode ist, dass der JSON mit der Zeit aufgebläht werden kann und Sie weiterhin alte Eigenschaften beibehalten müssen.

Es ist auch wichtig, Ihre "Rand" -Fälle für Ihre Kunden klar zu definieren. Angenommen, Sie haben eine Array-Eigenschaft namens "fooList". Die Eigenschaft "fooList" kann die folgenden möglichen Werte annehmen: existiert nicht / undefiniert (die Eigenschaft ist im JSON-Objekt nicht physisch vorhanden oder existiert und ist auf "undefiniert" gesetzt), null, leere Liste oder eine Liste mit einen oder mehrere Werte. Es ist wichtig, dass die Kunden verstehen, wie sie sich verhalten sollen, insbesondere in den Fällen undefiniert / null / leer.

Ich würde auch empfehlen, nachzulesen, wiesemantische Versionierungfunktioniert. Wenn Sie Ihren Versionsnummern ein semantisches Versionsschema hinzufügen, können abwärtskompatible Änderungen an einer Nebenversionsgrenze vorgenommen werden, während Änderungen an einer Hauptversionsgrenze vorgenommen werden können (sowohl Clients als auch Server müssten sich auf dieselbe Hauptversion einigen ). Dies ist zwar keine Eigenschaft von JSON selbst, dies ist jedoch nützlich, um die Arten von Änderungen zu kommunizieren, die ein Client erwarten sollte, wenn sich die Version ändert.

Quelle
Translate

Google basiert auf Javagson Bibliothekhat eine ausgezeichnete Versionierungsunterstützung für json. Es könnte sich als sehr praktisch erweisen, wenn Sie über Java nachdenken.

Es gibt ein schönes und einfaches TutorialHier.

Quelle
Translate

Verwenden Sie DataContractJsonSerializer nicht, wie der Name schon sagt. Die Objekte, die über diese Klasse verarbeitet werden, müssen:

a) Mit den Attributen [DataContract] und [DataMember] gekennzeichnet sein.

b) sich strikt an den definierten "Vertrag" halten, dh nicht weniger und nicht mehr, als er definiert ist. Jedes zusätzliche oder fehlende [DataMember] führt dazu, dass die Deserialisierung eine Ausnahme auslöst.

Wenn Sie flexibel genug sein möchten, verwenden Sie den JavaScriptSerializer, wenn Sie sich für die günstige Option entscheiden möchten ... oder verwenden Sie diese Bibliothek:

http://json.codeplex.com/

Dadurch haben Sie genügend Kontrolle über Ihre JSON-Serialisierung.

Stellen Sie sich vor, Sie haben ein Objekt in den frühen Tagen.

public class Customer
{ 
    public string Name;

    public string LastName;
}

Nach der Serialisierung sieht es folgendermaßen aus:

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

Wenn Sie Ihre Objektdefinition ändern, um Felder hinzuzufügen / zu entfernen. Die Deserialisierung erfolgt reibungslos, wenn Sie beispielsweise JavaScriptSerializer verwenden.

public class Customer
{ 
    public string Name;

    public string LastName;

    public int Age;
}

Wenn Sie versuchen, den letzten JSON für diese neue Klasse zu de-serialisieren, wird kein Fehler ausgegeben. Die Sache ist, dass Ihre neuen Felder auf ihre Standardeinstellungen gesetzt werden. In diesem Beispiel: "Alter" wird auf Null gesetzt.

Sie können in Ihren eigenen Konventionen ein Feld einfügen, das in allen Ihren Objekten vorhanden ist und die Versionsnummer enthält. In diesem Fall können Sie den Unterschied zwischen einem leeren Feld oder einer Versionsinkonsistenz erkennen.

Nehmen wir also an: Sie haben Ihre Klasse Customer v1 serialisiert:

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

Wenn Sie in eine Customer v2-Instanz deserialisieren möchten, haben Sie:

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

Sie können irgendwie erkennen, welche Felder in Ihrem Objekt irgendwie zuverlässig sind und welche nicht. In diesem Fall wissen Sie, dass Ihre v2-Objektinstanz von einer v1-Objektinstanz stammt, daher sollte dem Feld Alter nicht vertraut werden.

Ich denke daran, dass Sie auch ein benutzerdefiniertes Attribut verwenden sollten, z. B. "MinVersion", und jedes Feld mit der minimal unterstützten Versionsnummer markieren sollten, damit Sie ungefähr Folgendes erhalten:

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

    [MinVersion(1)]
    public string Name;

    [MinVersion(1)]
    public string LastName;

    [MinVersion(2)]
    public int Age;
}

Später können Sie dann auf diese Metadaten zugreifen und damit alles tun, was Sie benötigen.

Quelle
Translate

Es spielt keine Rolle, welches Serialisierungsprotokoll Sie verwenden, die Techniken zur Versionierung von APIs sind im Allgemeinen dieselben.

Im Allgemeinen benötigen Sie:

  1. eine Möglichkeit für den Verbraucher, dem Hersteller die von ihm akzeptierte API-Version mitzuteilen (obwohl dies nicht immer möglich ist)
  2. Eine Möglichkeit für den Hersteller, Versionsinformationen in die serialisierten Daten einzubetten
  3. Eine abwärtskompatible Strategie zur Behandlung unbekannter Felder

In einer Web-API ist im Allgemeinen die vom Verbraucher akzeptierte API-Version in den Accept-Header eingebettet (zAccept: application/vnd.myapp-v1+json application/vnd.myapp-v2+jsonbedeutet, dass der Verbraucher entweder Version 1 und Version 2 Ihrer API verarbeiten kann oder weniger häufig in der URL (zhttps://api.twitter.com/1/statuses/user_timeline.json). Dies wird im Allgemeinen für Hauptversionen verwendet (dh rückwärts inkompatible Änderungen). Wenn der Server und der Client keinen übereinstimmenden Accept-Header haben, schlägt die Kommunikation fehl (oder wird je nach Art der Anwendung nach besten Kräften fortgesetzt oder auf ein Standardbasisprotokoll zurückgegriffen).

Der Hersteller generiert dann serialisierte Daten in einer der angeforderten Versionen und bettet diese Versionsinformationen in die serialisierten Daten ein (z. B. als benanntes Feldversion). Der Verbraucher sollte die in die Daten eingebetteten Versionsinformationen verwenden, um zu bestimmen, wie die serialisierten Daten analysiert werden sollen. Die Versionsinformationen in den Daten sollten auch eine Nebenversion enthalten (dh für abwärtskompatible Änderungen). Im Allgemeinen sollten Verbraucher in der Lage sein, die Nebenversionsinformationen zu ignorieren und die Daten dennoch korrekt zu verarbeiten, obwohl das Verständnis der Nebenversion es dem Client ermöglichen kann, zusätzliche Annahmen zu treffen wie die Daten verarbeitet werden sollen.

Eine gängige Strategie zum Umgang mit unbekannten Feldern besteht darin, wie HTML und CSS analysiert werden. Wenn der Verbraucher unbekannte Felder sieht, sollte er diese ignorieren. Wenn den Daten ein vom Client erwartetes Feld fehlt, sollte ein Standardwert verwendet werden. Abhängig von der Art der Kommunikation möchten Sie möglicherweise auch einige obligatorische Felder angeben (dh fehlende Felder gelten als schwerwiegender Fehler). Felder, die in kleineren Versionen hinzugefügt werden, sollten immer optionale Felder sein. Die Nebenversion kann optionale Felder hinzufügen oder Felder semantisch ändern, solange sie abwärtskompatibel ist, während die Hauptversion Felder löschen oder Pflichtfelder hinzufügen oder die Feldsemantik rückwärts inkompatibel ändern kann.

In einem erweiterbaren Serialisierungsformat (wie JSON oder XML) sollten die Daten selbstbeschreibend sein, dh die Feldnamen sollten immer zusammen mit den Daten gespeichert werden. Sie sollten sich nicht darauf verlassen, dass bestimmte Daten für bestimmte Positionen verfügbar sind.

Quelle
Leave a Reply
You must be logged in to post a answer.
Über den Autor
Ted