serialization - Quelle est la meilleure façon de gérer la gestion des versions à l'aide du protocole JSON?

Translate

J'écris normalement toutes les parties du code en C # et lors de l'écriture de protocoles sérialisés, j'utilise FastSerializer qui sérialise / désérialise les classes rapidement et efficacement. Il est également très facile à utiliser, et assez simple à faire du «versionnage», c'est-à-dire à gérer différentes versions de la sérialisation. La chose que j'utilise normalement ressemble à ceci:

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

et

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

Il est donc facile d'ajouter de nouvelles choses, ou de changer complètement la sérialisation si on le souhaite.

Cependant, je souhaite maintenant utiliser JSON pour des raisons non pertinentes ici =) J'utilise actuellementDataContractJsonSerializeret je cherche maintenant un moyen d'avoir la même flexibilité que j'ai en utilisant le FastSerializer ci-dessus.

La question est donc; quelle est la meilleure façon de créer un protocole / sérialisation JSON et de pouvoir détailler la sérialisation comme ci-dessus, pour ne pas interrompre la sérialisation simplement parce qu'une autre machine n'a pas encore mis à jour sa version?

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

Toutes les réponses

Translate

La clé du contrôle de version JSON est de toujours ajouter de nouvelles propriétés, et de ne jamais supprimer ou renommer les propriétés existantes. Ceci est similaire àcomment les tampons de protocole gèrent la gestion des versions.

Par exemple, si vous avez commencé avec le JSON suivant:

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

Et vous voulez renommer la propriété "foo" en "bar", ne la renommez pas simplement. À la place, ajoutez une nouvelle propriété:

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

Étant donné que vous ne supprimez jamais de propriétés, les clients basés sur des versions plus anciennes continueront de fonctionner. L'inconvénient de cette méthode est que le JSON peut devenir gonflé au fil du temps et que vous devez continuer à conserver les anciennes propriétés.

Il est également important de définir clairement vos cas «marginaux» à vos clients. Supposons que vous ayez une propriété de tableau appelée "fooList". La propriété "fooList" pourrait prendre les valeurs possibles suivantes: n'existe pas / non défini (la propriété n'est pas physiquement présente dans l'objet JSON, ou elle existe et est définie sur "undefined"), null, liste vide ou une liste avec une ou plusieurs valeurs. Il est important que les clients comprennent comment se comporter, en particulier dans les cas non définis / null / vides.

Je recommanderais également de lire commentgestion des versions sémantiquetravaux. Si vous introduisez un schéma de versionnage sémantique dans vos numéros de version, des modifications rétrocompatibles peuvent être apportées à une limite de version mineure, tandis que des modifications importantes peuvent être apportées à une limite de version majeure (les clients et les serveurs devraient s'accorder sur la même version majeure ). Bien que ce ne soit pas une propriété du JSON lui-même, cela est utile pour communiquer les types de changements auxquels un client doit s'attendre lorsque la version change.

La source
Translate

Google basé sur Javabibliothèque gsona un excellent support de version pour json. Cela pourrait s'avérer très pratique si vous envisagez d'utiliser java.

Il y a un tutoriel agréable et facileici.

La source
Translate

N'utilisez pas DataContractJsonSerializer, comme son nom l'indique, les objets traités via cette classe devront:

a) Être marqué avec les attributs [DataContract] et [DataMember].

b) Être strictement conforme au «contrat» défini, c'est-à-dire rien de moins et rien de plus qu'il est défini. Tout [DataMember] supplémentaire ou manquant fera que la désérialisation lèvera une exception.

Si vous voulez être suffisamment flexible, utilisez le JavaScriptSerializer si vous voulez opter pour l'option bon marché ... ou utilisez cette bibliothèque:

http://json.codeplex.com/

Cela vous donnera un contrôle suffisant sur votre sérialisation JSON.

Imaginez que vous ayez un objet à ses débuts.

public class Customer
{ 
    public string Name;

    public string LastName;
}

Une fois sérialisé, il ressemblera à ceci:

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

Si vous modifiez la définition de votre objet pour ajouter / supprimer des champs. La désérialisation s'effectuera en douceur si vous utilisez, par exemple, JavaScriptSerializer.

public class Customer
{ 
    public string Name;

    public string LastName;

    public int Age;
}

Si vous essayez de désérialiser le dernier json dans cette nouvelle classe, aucune erreur ne sera générée. Le fait est que vos nouveaux champs seront définis sur leurs valeurs par défaut. Dans cet exemple: "Age" sera mis à zéro.

Vous pouvez inclure, dans vos propres conventions, un champ présent dans tous vos objets, qui contient le numéro de version. Dans ce cas, vous pouvez faire la différence entre un champ vide ou une incohérence de version.

Alors disons: vous avez votre classe Customer v1 sérialisée:

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

Vous souhaitez désérialiser en une instance Client v2, vous aurez:

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

Vous pouvez en quelque sorte détecter quels champs de votre objet sont en quelque sorte fiables et ce qui ne l'est pas. Dans ce cas, vous savez que votre instance d'objet v2 provient d'une instance d'objet v1, le champ Age ne doit donc pas être approuvé.

J'ai à l'esprit que vous devez également utiliser un attribut personnalisé, par exemple "MinVersion", et marquer chaque champ avec le numéro de version minimum pris en charge, de sorte que vous obtenez quelque chose comme ceci:

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

    [MinVersion(1)]
    public string Name;

    [MinVersion(1)]
    public string LastName;

    [MinVersion(2)]
    public int Age;
}

Ensuite, vous pourrez accéder à ces méta-données et faire tout ce dont vous pourriez avoir besoin avec cela.

La source
Translate

Peu importe le protocole de sérialisation que vous utilisez, les techniques de version des API sont généralement les mêmes.

Généralement, vous avez besoin:

  1. un moyen pour le consommateur de communiquer au producteur la version d'API qu'il accepte (bien que ce ne soit pas toujours possible)
  2. un moyen pour le producteur d'incorporer des informations de contrôle de version aux données sérialisées
  3. une stratégie rétrocompatible pour gérer les champs inconnus

Dans une API Web, la version de l'API acceptée par le consommateur est généralement intégrée dans l'en-tête Accept (par exempleAccept: application/vnd.myapp-v1+json application/vnd.myapp-v2+jsonsignifie que le consommateur peut gérer la version 1 et la version 2 de votre API) ou moins fréquemment dans l'URL (par exemplehttps://api.twitter.com/1/statuses/user_timeline.json). Ceci est généralement utilisé pour les versions majeures (c'est-à-dire les modifications incompatibles avec les versions antérieures). Si le serveur et le client n'ont pas d'en-tête Accept correspondant, la communication échoue (ou se déroule au mieux ou revient à un protocole de base par défaut, selon la nature de l'application).

Le producteur génère ensuite des données sérialisées dans l'une des versions demandées, puis intègre ces informations de version dans les données sérialisées (par exemple sous la forme d'un champ nomméversion). Le consommateur doit utiliser les informations de version intégrées dans les données pour déterminer comment analyser les données sérialisées. Les informations de version dans les données doivent également contenir une version mineure (c'est-à-dire pour les modifications rétrocompatibles), généralement les consommateurs doivent être en mesure d'ignorer les informations de version mineure et toujours traiter les données correctement, bien que la compréhension de la version mineure puisse permettre au client de faire des hypothèses supplémentaires sur comment les données doivent être traitées.

Une stratégie courante pour gérer les champs inconnus est comme la façon dont HTML et CSS sont analysés. Lorsque le consommateur voit un champ inconnu, il doit l'ignorer, et lorsque les données manquent un champ attendu par le client, il doit utiliser une valeur par défaut; selon la nature de la communication, vous pouvez également spécifier certains champs obligatoires (c'est-à-dire que les champs manquants sont considérés comme une erreur fatale). Les champs ajoutés dans les versions mineures doivent toujours être des champs facultatifs; La version mineure peut ajouter des champs facultatifs ou modifier les champs sémantiques tant qu'ils sont rétrocompatibles, tandis que la version majeure peut supprimer des champs ou ajouter des champs obligatoires ou modifier les champs sémantiques d'une manière rétrocompatible.

Dans un format de sérialisation extensible (comme JSON ou XML), les données doivent être auto-descriptives, en d'autres termes, les noms de champs doivent toujours être stockés avec les données; vous ne devez pas vous fier aux données spécifiques disponibles sur des postes spécifiques.

La source
Leave a Reply
You must be logged in to post a answer.
A propos de l'auteur
Ted