Partager via


Personnaliser le stockage de fichiers et la sérialisation XML

Lorsque l’utilisateur enregistre une instance ou modèle, d’un langage spécifique au domaine (DSL) dans Visual Studio, un fichier XML est créé ou mis à jour. Le fichier peut être rechargé pour recréer le modèle dans le Windows Store.

Vous pouvez personnaliser le schéma de sérialisation en ajustant les paramètres sous comportement de sérialisation Xml dans l’Explorateur DSL. Il existe un nœud sous Comportement de Sérialisation XML pour chaque classe de domaine, propriété et relation. Les relations sont situées sous leurs classes d'origine. Il existe également des nœuds correspondant aux classes de forme, de connecteur et de diagramme.

Vous pouvez également écrire du code de programme pour une personnalisation plus avancée.

Remarque

Si vous souhaitez enregistrer le modèle dans un format particulier, mais que vous n’avez pas besoin de le recharger à partir de ce formulaire, envisagez d’utiliser des modèles de texte pour générer la sortie du modèle, au lieu d’un schéma de sérialisation personnalisé. Pour plus d’informations, consultez Génération de code à partir d’un langage dédié.

Fichiers de modèle et de diagramme

Chaque modèle est enregistré dans deux fichiers :

  • Le fichier de modèle a un nom tel que Model1.mydsl. Il stocke les éléments et relations du modèle et leurs propriétés. L’extension de fichier telle que .mydsl est déterminée par la propriété FileExtension du nœud éditeur dans la définition DSL.

  • Le fichier de diagramme a un nom tel que Model1.mydsl.diagram. Il stocke les formes, les connecteurs et leurs positions, couleurs, épaisseurs de trait et autres détails de l’apparence du diagramme. Si l’utilisateur supprime un fichier .diagram, les informations essentielles du modèle ne sont pas perdues. Seule la disposition du diagramme est perdue. Lorsque le fichier de modèle est ouvert, un ensemble par défaut de formes et de connecteurs est créé.

Pour modifier l’extension de fichier d’un DSL

  1. Ouvrez la définition DSL. Dans l’Explorateur DSL, cliquez sur le nœud Éditeur.

  2. Dans la fenêtre Propriétés, modifiez la propriété FileExtension. N’incluez pas la . initiale de l’extension de nom de fichier.

  3. Dans l’Explorateur de solutions, modifiez le nom des deux fichiers de modèle d’élément dans DslPackage\ProjectItemTemplates. Ces fichiers ont des noms qui suivent ce format :

    myDsl.diagram

    myDsl.myDsl

Schéma de sérialisation par défaut

Pour créer un exemple pour cette rubrique, la définition DSL suivante a été utilisée.

diagramme de définition DSL - modèle d'arbre de famille

Cette définition DSL a été utilisée pour créer un modèle qui présente l’apparence suivante à l’écran.

diagramme d’arborescence familiale, boîte à outils et explorateur

Ce modèle a été enregistré, puis rouvert dans l’éditeur de texte XML :

<?xml version="1.0" encoding="utf-8"?>
<familyTreeModel xmlns:dm0="http://schemas.microsoft.com/VisualStudio/2008/DslTools/Core" dslVersion="1.0.0.0" Id="f817b728-e920-458e-bb99-98edc469d78f" xmlns="http://schemas.microsoft.com/dsltools/FamilyTree">
  <people>
    <person name="Henry VIII" birthYear="1491" deathYear="1547" age="519">
      <children>
        <personMoniker name="/f817b728-e920-458e-bb99-98edc469d78f/Elizabeth I" />
        <personMoniker name="/f817b728-e920-458e-bb99-98edc469d78f/Mary" />
      </children>
    </person>
    <person name="Elizabeth I" birthYear="1533" deathYear="1603" age="477" />
    <person name="Mary" birthYear="1515" deathYear="1558" age="495" />
  </people>
</familyTreeModel>

Notez les points suivants sur le modèle sérialisé :

  • Chaque nœud XML a un nom identique à un nom de classe de domaine, sauf que la lettre initiale est en minuscules. Par exemple, familyTreeModel et person.

  • Les propriétés de domaine telles que Name et BirthYear sont sérialisées en tant qu’attributs dans les nœuds XML. Là encore, le caractère initial du nom de propriété est converti en minuscules.

  • Chaque relation est sérialisée sous la forme d’un nœud XML imbriqué à l’intérieur de l’extrémité source de la relation. Le nœud a le même nom que la propriété de rôle source, mais avec un caractère initial en minuscules.

    Par exemple, un rôle nommé People dans la définition DSL provient de la classe FamilyTree. Dans le code XML, le rôle Personnes est représenté avec un nœud nommé people imbriqué à l’intérieur du nœud familyTreeModel.

  • L’extrémité cible de chaque imbrication de la relation est sérialisée sous la forme d’un nœud imbriqué sous la relation. Par exemple, le nœud people contient plusieurs nœuds person.

  • L’extrémité cible de chaque relation de référence est sérialisée sous forme de moniker, qui encode une référence à l’élément cible.

    Par exemple, sous un nœud person, il peut y avoir une relation children. Ce nœud contient des monikers tels que :

    <personMoniker name="/f817b728-e920-458e-bb99-98edc469d78f/Elizabeth I" />
    

Présentation des monikers

Les monikers sont utilisés pour représenter des références croisées entre différentes parties du modèle et des fichiers de diagramme. Ils sont également utilisés dans le fichier .diagram pour faire référence à des nœuds dans le fichier de modèle. Il existe deux formes de moniker :

  • Les monikers d’ID citent le GUID de l’élément cible. Par exemple:

    <personShapeMoniker Id="f79734c0-3da1-4d72-9514-848fa9e75157" />
    
  • Les monikers de clé qualifiés identifient l’élément cible par la valeur d’une propriété de domaine désignée appelée clé de moniker. Le moniker de l’élément cible est précédé du moniker de son élément parent dans l’arborescence des relations d’incorporation.

    Les exemples suivants sont extraits d’une DSL dans laquelle il existe une classe de domaine nommée Album, qui a une relation d’incorporation à une classe de domaine nommée Song :

    <albumMoniker title="/My Favorites/Jazz after Teatime" />
    <songMoniker title="/My Favorites/Jazz after Teatime/Hot tea" />
    

    Des monikers de clé qualifiés sont utilisés si la classe cible a une propriété de domaine pour laquelle l’option Is Moniker Key est définie sur true dans comportement de sérialisation Xml. Dans l’exemple, cette option est définie pour les propriétés de domaine nommées « Title » dans les classes de domaine « Album » et « Song ».

Les identifiants clés qualifiés sont plus faciles à lire que les identifiants d'identification. Si vous prévoyez que le code XML de vos fichiers de modèle soit lisible par l’homme, envisagez d’utiliser des monikers clés qualifiés. Toutefois, il est possible pour l’utilisateur de définir plusieurs éléments pour avoir la même clé moniker. Les clés en double pourraient empêcher le fichier de se recharger correctement. Par conséquent, si vous définissez une classe de domaine référencée à l’aide de monikers de clés qualifiés, vous devez envisager des façons d’empêcher l’utilisateur d’enregistrer un fichier qui a des monikers en double.

Pour définir une classe de domaine à référencer par des monikers d’ID

  1. Assurez-vous que Is Moniker Key est false pour chaque propriété de domaine dans la classe et ses classes de base.

    1. Dans l’Explorateur DSL, développez Xml Serialization Behavior\Class Data\<classe de domaine>\Element Data.

    2. Vérifiez que is Moniker Key a la valeur false pour chaque propriété de domaine.

    3. Si la classe de domaine a une classe de base, répétez la procédure dans cette classe.

  2. Configurez l'identifiant de sérialisation = true pour la classe de domaine.

    Cette propriété se trouve sous Gestion de la sérialisation XML.

Pour définir une classe de domaine à référencer par des monikers de clés qualifiés

  • Définissez comme clé de moniker pour une propriété de domaine d’une classe de domaine existante. Le type de la propriété doit être string.

    1. Dans l’Explorateur DSL, développez Xml Serialization Behavior\Class Data\<classe de domaine>\Element Data, puis sélectionnez la propriété de domaine.

    2. Dans la fenêtre Propriétés, définissez Is Moniker Key sur true.

  • ou

    Utilisez l'outil Classe de Domaine Nommée pour créer une nouvelle classe de domaine.

    Cet outil crée une classe qui a une propriété de domaine appelée Name. Les propriétés Is Element Name et Is Moniker Key de cette propriété de domaine sont initialisées pour true.

  • ou

    Créez une relation d’héritage de la classe de domaine vers une autre classe qui a une propriété de clé moniker.

Prévention des doublons de monikers

Si vous utilisez des monikers de clés qualifiés, il est possible que deux éléments du modèle d’un utilisateur aient la même valeur dans la clé de propriété. Par exemple, si votre DSL a une personne de classe qui a un nom de propriété, l’utilisateur peut définir les noms de deux éléments comme étant identiques. Bien que le modèle puisse être enregistré dans le fichier, il ne serait pas rechargé correctement.

Il existe plusieurs méthodes qui permettent d’éviter cette situation :

  • Définissez comme nom de l'élément = true pour la propriété de clé de domaine. Sélectionnez la propriété de domaine dans le diagramme de définition DSL, puis définissez la valeur dans la fenêtre Propriétés.

    Lorsque l’utilisateur crée une instance de la classe, cette valeur entraîne l’attribution automatique d’une valeur différente à la propriété de domaine. Le comportement par défaut ajoute un nombre à la fin du nom de classe. Cela n’empêche pas l’utilisateur de changer le nom en doublon, mais cela peut être utile dans le cas où l’utilisateur ne définit pas la valeur avant d’enregistrer le modèle.

  • Activez la validation pour la DSL. Dans l’Explorateur DSL, sélectionnez Éditeur\Validation, puis définissez les propriétés Utilisations... sur true.

    Il existe une méthode de validation générée automatiquement qui vérifie les ambiguïtés. La méthode se trouve dans la catégorie de validation Load. Cela permet de s’assurer que l’utilisateur sera averti qu’il n’est peut-être pas possible de rouvrir le fichier.

    Pour plus d’informations, consultez Validation dans un langage spécifique au domaine.

Chemins et qualificateurs de monikers

Un moniker de clé qualifié se termine par la clé de moniker et est préfixé par le moniker de son parent dans l’arborescence d’incorporation. Par exemple, si le moniker d’un album est :

<albumMoniker title="/My Favorites/Jazz after Teatime" />

Ensuite, l’une des chansons de cet album pourrait être :

<songMoniker title="/My Favorites/Jazz after Teatime/Hot tea" />

Toutefois, si les albums sont référencés par ID à la place, les monikers sont les suivants :

<albumMoniker Id="77472c3a-9bf9-4085-976a-d97a4745237c" />
<songMoniker title="/77472c3a-9bf9-4085-976a-d97a4745237c/Hot tea" />

Notez que, étant donné qu’un GUID est unique, il n’est jamais préfixé par le moniker de son parent.

Si vous savez qu’une propriété de domaine particulière aura toujours une valeur unique dans un modèle, vous pouvez définir Is Moniker Qualifier sur true pour cette propriété. Cela lui permet d’être utilisé comme qualificateur, sans utiliser le moniker du parent. Par exemple, si vous définissez à la fois Is Moniker Qualifier et Is Moniker Key pour la propriété Title de la classe Album, le nom ou l'identifiant du modèle n'est pas utilisé dans les identifiants pour Album et ses enfants intégrés :

<albumMoniker name="Jazz after Teatime" />
<songMoniker title="/Jazz after Teatime/Hot tea" />

Personnaliser la structure du code XML

Pour effectuer les personnalisations suivantes, développez le nœud Xml Serialization Behavior dans l’Explorateur DSL. Sous une classe de domaine, développez le nœud Données d’élément pour afficher la liste des propriétés et des relations provenant de cette classe. Sélectionnez une relation et ajustez ses options dans la fenêtre Propriétés.

  • Définissez Omit Element sur true pour omettre le nœud de rôle source, en laissant uniquement la liste des éléments cibles. Vous ne devez pas définir cette option s’il existe plusieurs relations entre les classes source et cible.

    <familyTreeModel ...>
      <!-- The following node is omitted by using Omit Element: -->
      <!-- <people> -->
        <person name="Henry VIII" .../>
        <person name="Elizabeth I" .../>
      <!-- </people> -->
    </familyTreeModel>
    
  • Définissez Utiliser le formulaire complet pour incorporer les nœuds cibles dans les nœuds représentant les instances de relation. Cette option est définie automatiquement lorsque vous ajoutez des propriétés de domaine à une relation de domaine.

    <familyTreeModel ...>
      <people>
        <!-- The following node is inserted by using Use Full Form: -->
        <familyTreeModelHasPeople myRelationshipProperty="x1">
          <person name="Henry VIII" .../>
        </familyTreeModelHasPeople>
        <familyTreeModelHasPeople myRelationshipProperty="x2">
          <person name="Elizabeth I" .../>
        </familyTreeModelHasPeople>
      </people>
    </familyTreeModel>
    
  • Définissez Representation = Element pour qu’une propriété de domaine soit enregistrée en tant qu’élément au lieu d’une valeur d’attribut.

    <person name="Elizabeth I" birthYear="1533">
      <deathYear>1603</deathYear>
    </person>
    
  • Pour modifier l’ordre dans lequel les attributs et les relations sont sérialisés, cliquez avec le bouton droit sur un élément sous Données d’élément, puis utilisez les commandes Déplacer vers le haut ou déplacer vers le bas commandes de menu.

Personnalisation majeure à l’aide du code du programme

Vous pouvez remplacer des parties ou tous les algorithmes de sérialisation.

Nous vous recommandons d’étudier le code dans Dsl\Generated Code\Serializer.cs et SerializationHelper.cs.

Pour personnaliser la sérialisation d’une classe particulière

  1. Définissez Is Custom dans le nœud de cette classe sous Xml Serialization Behavior.

  2. Transformez tous les modèles, générez la solution et examinez les erreurs de compilation résultantes. Les commentaires proches de chaque erreur expliquent le code que vous devez fournir.

Spécification d’une sérialisation personnalisée pour l’ensemble du modèle

  1. Remplacez les méthodes présentes dans Dsl\GeneratedCode\SerializationHelper.cs.

Remarque

À compter de Visual Studio 2022 17.13, l’implémentation de sérialisation par défaut ne prend plus en charge la sérialisation ou la désérialisation des types de données personnalisés à l’aide de BinaryFormatter en raison de risques de sécurité avec BinaryFormatter.

Si vous utilisez un type de données personnalisé pour toutes les propriétés de domaine, vous devez remplacer les méthodes de sérialisation dans la classe SerializationHelper, ou implémenter un TypeConverter capable de convertir chaque type de données personnalisé en et à partir d’une chaîne.

Même si nous vous déconseillons d’utiliser BinaryFormatter pour des raisons de sécurité, si vous devez maintenir la compatibilité descendante avec les modèles plus anciens utilisés BinaryFormatter sérialisation, vous pouvez implémenter un TypeConverter qui désérialise les données binaires. L’extrait de code suivant sert de modèle pour implémenter cette compatibilité :

class MyCustomDataTypeConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value is string text)
        {
            // First, try to parse the string as if it were returned by MyCustomDataType.ToString().
            if (MyCustomDataType.TryParse(text, out var custom))
                return custom;

            // Fall back to trying to deserialize the old BinaryFormatter serialization format.
            var decoded = Convert.FromBase64String(text);
            using (var memory = new MemoryStream(decoded, false))
            {
                var binaryFormatter = new BinaryFormatter();
                return binaryFormatter.Deserialize(memory) as MyCustomDataType;
            }
        }

        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(string) && value is MyCustomDataType custom)
            return custom.ToString();

        return base.ConvertTo(context, culture, value, destinationType);
    }
}

// ...

[TypeConverter(MyCustomDataTypeConverter)]
class MyCustomDataType
{
    // ...
}

Options dans le comportement de sérialisation Xml

Dans l’Explorateur DSL, le nœud Xml Serialization Behavior contient un nœud enfant pour chaque classe de domaine, relation, forme, connecteur et classe de diagramme. Sous chacun de ces nœuds se trouve une liste des propriétés et des relations associées à cet élément. Les relations sont représentées à la fois en tant que telles et dans leurs classes sources.

Le tableau suivant récapitule les options que vous pouvez définir dans cette section de la définition DSL. Dans chaque cas, sélectionnez un élément dans l’Explorateur DSL et définissez les options dans la fenêtre Propriétés.

Données de classe Xml

Ces éléments se trouvent dans l’Explorateur DSL sous Comportement de Sérialisation XML\Données de Classe.

Propriété Description
Possède un schéma d’élément personnalisé Si la valeur est True, indique que la classe de domaine a un schéma d’élément personnalisé
Est personnalisé Définissez la valeur sur True si vous souhaitez écrire votre propre code de sérialisation et de désérialisation pour cette classe de domaine.

Générez la solution et examinez les erreurs pour découvrir des instructions détaillées.
Classe de domaine Classe de domaine à laquelle ce nœud de données de classe s’applique. Lecture seule.
Nom de l’élément Nom du nœud Xml pour les éléments de cette classe. La valeur par défaut est une version minuscule du nom de classe de domaine.
Nom de l’attribut Moniker Nom de l’attribut utilisé dans les éléments moniker pour contenir la référence. S'il est vide, le nom de la clé de propriété ou l'ID est utilisé.

Dans cet exemple, il s’agit de « name » : <personMoniker name="/Mike Nash"/>
Nom de l’élément Moniker Nom de l’élément xml utilisé pour les monikers qui font référence aux éléments de cette classe.

La valeur par défaut est une version minuscule du nom de classe suffixe « Moniker ». Par exemple, personMoniker.
Nom du type de moniker Nom du type xsd généré pour les monikers des éléments de cette classe. Le XSD se trouve dans Dsl\Generated Code\*Schema.xsd
Sérialiser l’ID Si la valeur est True, le GUID de l’élément est inclus dans le fichier. La valeur doit être définie sur Vrai s’il n’existe aucune propriété marquée Is Moniker Key et la DSL définit les relations de référence avec cette classe.
Nom du type Nom du type xml généré dans le xsd à partir de la classe de domaine désignée.
Notes Notes informelles associées à cet élément

Données de propriété Xml

Les nœuds de propriété Xml se trouvent sous les nœuds de classe.

Propriété Description
Propriété de domaine Propriété à laquelle les données de configuration de sérialisation xml s’appliquent. Lecture seule.
Is Moniker Key Si la valeur est définie sur True, la propriété est utilisée comme clé pour créer des monikers qui référencent des instances de cette classe de domaine.
Is Moniker Qualifier Si la valeur est définie sur True, la propriété est utilisée pour créer le qualificateur dans les monikers. Si la valeur est false et si SerializeId n’est pas true pour cette classe de domaine, les monikers sont qualifiés par le moniker de l’élément parent dans l’arborescence d’incorporation.
Représentation Si la valeur est définie sur attribut, la propriété est sérialisée en tant qu’attribut xml ; si la valeur est définie sur 'élément, elle est sérialisée en tant qu’élément ; si la valeur est définie sur Ignorer, elle n’est pas sérialisée.
Nom XML Nom utilisé pour l’attribut xml ou l’élément représentant la propriété. Par défaut, la valeur est une version minuscule du nom de propriété de domaine.
Notes Notes informelles associées à cet élément

Données de rôle XML

Les nœuds de données de rôle se trouvent sous les nœuds de classe source.

Propriété Description
Has Custom Moniker Définissez cette valeur sur true si vous souhaitez fournir votre propre code pour générer et résoudre des monikers qui parcourent cette relation.

Pour obtenir des instructions détaillées, générez la solution, puis double-cliquez sur les messages d’erreur.
Relation de domaine Spécifie la relation à laquelle ces options s’appliquent. Lecture seule.
Omettre élément Si la valeur est true, le nœud XML qui correspond au rôle source est omis du schéma.

S’il existe plusieurs relations entre les classes source et cible, ce nœud de rôle fait la distinction entre les liens qui appartiennent aux deux relations. Nous vous recommandons donc de ne pas définir cette option dans ce cas.
Nom de l'élément de rôle Spécifie le nom de l’élément XML dérivé du rôle source. La valeur par défaut est le nom de la propriété de rôle.
Utiliser le formulaire complet Si la valeur est vraie, chaque élément cible ou moniker est enveloppé dans un nœud XML représentant la relation. Cette valeur doit être définie sur true si la relation a ses propres propriétés de domaine.