Partager via


Meilleures pratiques : Gestion des versions des contrats de données

Cette rubrique répertorie les meilleures pratiques pour créer des contrats de données qui peuvent évoluer facilement au fil du temps. Pour plus d’informations sur les contrats de données, consultez les rubriques de l’utilisation de contrats de données.

Remarque sur la validation de schéma

Lors de la discussion du contrôle de version des contrats de données, il est important de noter que le schéma de contrat de données exporté par Windows Communication Foundation (WCF) n’a aucune prise en charge du contrôle de version, autre que le fait que les éléments soient marqués comme facultatifs par défaut.

Cela signifie que même le scénario de contrôle de version le plus courant, comme l’ajout d’un nouveau membre de données, ne peut pas être implémenté de manière transparente en ce qui concerne un schéma donné. Les versions plus récentes d’un contrat de données (avec un nouveau membre de données, par exemple) ne sont pas validées à l’aide de l’ancien schéma.

Toutefois, il existe de nombreux scénarios dans lesquels la conformité stricte du schéma n’est pas nécessaire. De nombreuses plateformes de services Web, notamment WCF et XML Web créées à l’aide de ASP.NET, n’effectuent pas de validation de schéma par défaut et tolèrent donc des éléments supplémentaires qui ne sont pas décrits par le schéma. Lors de l’utilisation de ces plateformes, de nombreux scénarios de contrôle de version sont plus faciles à implémenter.

Par conséquent, il existe deux ensembles de directives de contrôle de version de contrat de données : un ensemble pour les scénarios où la validité stricte du schéma est importante, et un autre ensemble pour les scénarios quand ce n’est pas le cas.

Contrôle de version lorsque la validation du schéma est requise

Si la validité stricte du schéma est requise dans toutes les directions (nouveau-à-ancien et ancien à nouveau), les contrats de données doivent être considérés comme immuables. Si le contrôle de version est requis, un nouveau contrat de données doit être créé, avec un nom ou un espace de noms différent, et le contrat de service utilisant le type de données doit être versionné en conséquence.

Par exemple, un contrat de service de traitement de bon de commande nommé PoProcessing avec une PostPurchaseOrder opération prend un paramètre conforme à un PurchaseOrder contrat de données. Si le PurchaseOrder contrat doit changer, vous devez créer un contrat de données, autrement dit, PurchaseOrder2qui inclut les modifications. Vous devez ensuite gérer le contrôle de version au niveau du contrat de service. Par exemple, en créant une PostPurchaseOrder2 opération qui accepte le PurchaseOrder2 paramètre ou en créant un PoProcessing2 contrat de service où l’opération PostPurchaseOrder prend un PurchaseOrder2 contrat de données.

Notez que les modifications apportées aux contrats de données référencés par d’autres contrats de données s’étendent également à la couche de modèle de service. Par exemple, dans le scénario précédent, le PurchaseOrder contrat de données n’a pas besoin de changer. Toutefois, il contient un membre de données d’un Customer contrat de données, qui à son tour contenait un membre de données du Address contrat de données, qui doit être modifié. Dans ce cas, vous devez créer un Address2 contrat de données avec les modifications requises, un Customer2 contrat de données qui contient le Address2 membre de données et un PurchaseOrder2 contrat de données qui contient un Customer2 membre de données. Comme dans le cas précédent, le contrat de service doit également être versionné.

Bien que dans ces exemples, les noms soient modifiés (en ajoutant un « 2 »), la recommandation consiste à modifier les espaces de noms au lieu de noms en ajoutant de nouveaux espaces de noms avec un numéro de version ou une date. Par exemple, le contrat de données http://schemas.contoso.com/2005/05/21/PurchaseOrder passe au contrat de données http://schemas.contoso.com/2005/10/14/PurchaseOrder.

Pour plus d’informations, consultez Meilleures pratiques : Gestion des versions de service.

Parfois, vous devez garantir une conformité stricte du schéma pour les messages envoyés par votre application, mais vous ne pouvez pas compter sur les messages entrants pour qu’ils soient strictement conformes au schéma. Dans ce cas, un message entrant peut contenir des données superflues. Les valeurs superflues sont stockées et retournées par WCF, ce qui entraîne l’envoi de messages non valides par le schéma. Pour éviter ce problème, la fonctionnalité d’aller-retour doit être désactivée. Deux méthodes s’offrent à vous pour ce faire.

Pour plus d’informations sur l’aller-retour, consultez Forward-Compatible Contrats de données.

Contrôle de version lorsque la validation du schéma n’est pas requise

La conformité stricte du schéma est rarement requise. De nombreuses plateformes tolèrent des éléments supplémentaires non décrits par un schéma. Tant que cela est toléré, l’ensemble complet de fonctionnalités décrites dans le contrôle de version des contrats de données etForward-Compatible contrats de données peut être utilisé. Les instructions suivantes sont recommandées.

Certaines des instructions doivent être suivies exactement pour envoyer de nouvelles versions d’un type où un ancien est attendu ou envoyer un ancien dans lequel le nouveau est attendu. D’autres instructions ne sont pas strictement requises, mais sont répertoriées ici, car elles peuvent être affectées par l’avenir du contrôle de version de schéma.

  1. Ne tentez pas de gérer les versions des contrats de données selon l'héritage de types. Pour créer des versions ultérieures, modifiez le contrat de données sur un type existant ou créez un nouveau type non lié.

  2. L’utilisation de l’héritage avec des contrats de données est autorisée, à condition que l’héritage ne soit pas utilisé comme mécanisme de contrôle de version et que certaines règles sont suivies. Si un type dérive d’un certain type de base, ne le faites pas dériver d’un type de base différent dans une version ultérieure (sauf s’il a le même contrat de données). Il existe une exception à ceci : vous pouvez insérer un type dans la hiérarchie entre un type de contrat de données et son type de base, mais uniquement s’il ne contient pas de membres de données portant les mêmes noms que d’autres membres dans toutes les versions possibles des autres types de la hiérarchie. En général, l’utilisation de membres de données portant les mêmes noms à différents niveaux de la même hiérarchie d’héritage peut entraîner des problèmes sérieux de contrôle de version et doit être évité.

  3. À partir de la première version d'un contrat de données, implémentez toujours IExtensibleDataObject pour activer l'aller-retour. Pour plus d’informations, consultez Forward-Compatible Contrats de données. Si vous avez publié une ou plusieurs versions d’un type sans implémenter cette interface, implémentez-la dans la prochaine version du type.

  4. Dans les versions ultérieures, ne modifiez pas le nom ou l’espace de noms du contrat de données. Si vous modifiez le nom ou l’espace de noms du type sous-jacent au contrat de données, veillez à conserver le nom et l’espace de noms du contrat de données à l’aide des mécanismes appropriés, tels que la Name propriété du DataContractAttribute. Pour plus d’informations sur l’affectation de noms, consultez Noms des contrats de données.

  5. Dans les versions ultérieures, ne modifiez pas les noms des membres de données. Si vous modifiez le nom du champ, de la propriété ou de l’événement sous-jacent au membre de données, utilisez la Name propriété de DataMemberAttribute celle-ci pour conserver le nom de membre de données existant.

  6. Dans les versions ultérieures, ne modifiez pas le type d’un champ, d’une propriété ou d’un événement sous-jacent à un membre de données de sorte que le contrat de données résultant pour ce membre de données change. N’oubliez pas que les types d’interface sont équivalents aux Object fins de la détermination du contrat de données attendu.

  7. Dans les versions ultérieures, ne modifiez pas l’ordre des membres de données existants en ajustant la Order propriété de l’attribut DataMemberAttribute .

  8. Dans les versions ultérieures, de nouveaux membres de données peuvent être ajoutés. Ils doivent toujours suivre ces règles :

    1. La IsRequired propriété doit toujours être laissée à sa valeur par défaut .false

    2. Si une valeur par défaut de null ou de zéro pour le membre est inacceptable, une méthode de rappel doit être fournie à l’aide de OnDeserializingAttribute pour offrir une valeur par défaut raisonnable si le membre n’est pas présent dans le flux entrant. Pour plus d’informations sur le rappel, consultez Rappels de sérialisation avec tolérance de version.

    3. La DataMemberAttribute.Order propriété doit être utilisée pour vous assurer que tous les membres de données nouvellement ajoutés apparaissent après les membres de données existants. La méthode recommandée est la suivante : Aucun des membres de données de la première version du contrat de données ne doit avoir leur Order propriété définie. Tous les membres de données ajoutés dans la version 2 du contrat de données doivent avoir leur Order propriété définie sur 2. Tous les membres de données ajoutés dans la version 3 du contrat de données doivent avoir leur Order valeur 3, et ainsi de suite. Il est permis d’avoir plusieurs membres de données affectés au même Order nombre.

  9. Ne supprimez pas de membres de données dans les versions ultérieures, même si la propriété IsRequired conserve sa propriété false par défaut dans les versions antérieures.

  10. Ne modifiez pas la IsRequired propriété sur les membres de données existants d'une version à une autre.

  11. Pour les membres de données requis (où IsRequired est true), ne modifiez pas la propriété EmitDefaultValue d'une version à l'autre.

  12. N’essayez pas de créer des hiérarchies de gestion de versions branchées. Autrement dit, il doit toujours y avoir un chemin d’accès dans au moins une direction de n’importe quelle version vers n’importe quelle autre version en utilisant uniquement les modifications autorisées par ces instructions.

    Par exemple, si la version 1 d’un contrat de données de personne contient uniquement le membre de données Name, vous ne devez pas créer la version 2a du contrat en ajoutant uniquement le membre Age et la version 2b en ajoutant uniquement le membre Address. Passer de 2a à 2b implique la suppression de l’âge et l’ajout d’adresse ; aller dans l’autre direction implique la suppression d’Adresse et l’ajout d’Age. La suppression de membres n’est pas autorisée par ces instructions.

  13. Vous ne devez généralement pas créer de sous-types de types de contrats de données existants dans une nouvelle version de votre application. De même, vous ne devez pas créer de contrats de données utilisés à la place des membres de données déclarés en tant que types d’objets ou d’interface. La création de ces nouvelles classes est autorisée uniquement lorsque vous savez que vous pouvez ajouter les nouveaux types à la liste des types connus de toutes les instances de votre ancienne application. Par exemple, dans la version 1 de votre application, vous pouvez avoir le type de contrat de données LibraryItem avec les sous-types de contrat de données Livre et Journal. LibraryItem aurait alors une liste de types connus qui contient le livre et le journal. Supposons que vous ajoutez maintenant un type magazine dans la version 2, qui est un sous-type de LibraryItem. Si vous envoyez une instance magazine de la version 2 à la version 1, le contrat de données magazine est introuvable dans la liste des types connus et une exception est levée.

  14. Vous ne devez pas ajouter ou supprimer des membres d’énumération entre les versions. Vous ne devez pas également renommer les membres d’énumération, sauf si vous utilisez la propriété Name sur l’attribut EnumMemberAttribute pour conserver leurs noms dans le modèle de contrat de données identique.

  15. Les collections sont interchangeables dans le modèle de contrat de données, comme décrit dans Les types de collecte dans les contrats de données. Cela permet un grand degré de flexibilité. Toutefois, assurez-vous que vous ne modifiez pas par inadvertance un type de collection d’une manière non interchangeable de la version à la version. Par exemple, ne passez pas d’une collection non personnalisée (autrement dit, sans l’attribut CollectionDataContractAttribute ) à une collection personnalisée ou à une collection personnalisée à une collection non personnalisée. En outre, ne modifiez pas les propriétés d'une version à l'autre CollectionDataContractAttribute. La seule modification autorisée consiste à ajouter une propriété Name ou Namespace si le nom ou l’espace de noms du type de collection sous-jacent a changé et que vous devez définir son nom de contrat de données et son espace de noms comme dans une version précédente.

Certaines des directives répertoriées ici peuvent être ignorées en toute sécurité lorsque des circonstances spéciales s’appliquent. Veillez à bien comprendre les mécanismes de sérialisation, de désérialisation et de schéma impliqués avant de dévier des instructions.

Voir aussi