Personnaliser le stockage de fichiers et la sérialisation XML
Lorsque l’utilisateur enregistre une instance, ou un modèle, d’un langage dédié (DSL) dans Visual Studio, un fichier XML est créé ou mis à jour. Ce fichier peut être rechargé pour recréer le modèle dans le Store.
Vous pouvez personnaliser le schéma de sérialisation en ajustant les paramètres sous Xml Serialization Behavior 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 se trouvent dans leur classe source. Il existe également des nœuds correspondant aux classes de forme, de connecteur et de diagramme.
Vous pouvez aussi écrire du code de programme pour une personnalisation plus avancée.
Notes
Si vous souhaitez enregistrer le modèle dans un format particulier, mais que vous n’avez pas besoin de le recharger sous cette forme, vous pouvez 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 de modèle et les relations, ainsi que leurs propriétés. L’extension de fichier telle qu’elle.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, les couleurs, les épaisseurs de trait et d’autres informations sur l’apparence du diagramme. Si l’utilisateur supprime un.diagram
fichier, les informations essentielles dans le modèle ne sont pas perdues. Seule la disposition du diagramme l’est. Lorsque le fichier de modèle est ouvert, un ensemble par défaut de formes et de connecteurs est créé.
Modification de l’extension de fichier d’une définition DSL
Ouvrez la définition DSL. Dans l’Explorateur DSL, cliquez sur le nœud Éditeur.
Dans la fenêtre Propriétés, modifiez la propriété FileExtension. N’incluez pas l’extension de nom de fichier initiale
.
.Dans l’Explorateur de solutions, modifiez le nom des deux fichiers de modèle d’élément dans DslPackage\ProjectItemTemplates. Ces fichiers portent des noms conformes au format suivant :
myDsl.diagram
myDsl.myDsl
Schéma de sérialisation par défaut
La définition DSL utilisée pour créer un exemple dans cette rubrique est la suivante.
Cette définition DSL a été utilisée pour créer un modèle qui présente l’apparence suivante à l’écran.
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 concernant le modèle sérialisé :
Chaque nœud XML porte un nom identique à un nom de classe de domaine, à ceci près que la lettre initiale est en minuscules. Par exemple :
familyTreeModel
etperson
.Les propriétés de domaine telles que Name et BirthYear sont sérialisées sous forme d’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 porte 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 Contacts est représenté avec un nœud nommé
people
imbriqué à l’intérieur dufamilyTreeModel
nœud.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œudsperson
.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, il peut y avoir une relation
children
sous un nœudperson
. Ce nœud contient différents monikers :<personMoniker name="/f817b728-e920-458e-bb99-98edc469d78f/Elizabeth I" />
Présentation des monikers
Les monikers permettent de représenter des références croisées entre différentes parties des fichiers de modèle et de diagramme. Ils sont également utilisés dans le .diagram
fichier pour faire référence à des nœuds dans le fichier de modèle. Il existe deux formes de monikers :
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" />
Les monikers de clé qualifiés sont utilisés si la classe cible a une propriété de domaine pour laquelle l’option Est la clé Moniker est définie
true
dans le 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 monikers de clé qualifiés sont plus faciles à lire que les monikers d’ID. 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 doublons de clés peuvent empêcher le rechargement du fichier. Par conséquent, si vous définissez une classe de domaine à laquelle font référence des monikers de clé qualifiés, vous devez envisager des moyens d’empêcher l’utilisateur d’enregistrer un fichier contenant des monikers en double.
Définition d’une classe de domaine à laquelle feront référence des monikers d’ID
Assurez-vous que Is Moniker Key a la valeur
false
pour chacune des propriétés de domaine de la classe et de ses classes de base.Dans l’Explorateur DSL, développez Xml Serialization Behavior\Class Data\<classe de domaine>\Element Data.
Vérifiez que is Moniker Key a la valeur
false
pour chaque propriété de domaine.Si la classe de domaine possède une classe de base, répétez la procédure dans cette classe.
Définissez la propriété Serialize Id =
true
de la classe de domaine.Cette propriété se trouve sous Xml Serialization Behavior.
Définition d’une classe de domaine à laquelle feront référence des monikers de clé qualifiés
Définissez Is Moniker Key pour une propriété de domaine d’une classe de domaine existante. Le type de la propriété doit être
string
.Dans l’Explorateur DSL, développez Xml Serialization Behavior\Class Data\<classe de domaine>\Element Data, puis sélectionnez la propriété de domaine.
Dans la fenêtre Propriétés, définissez Is Moniker Key sur
true
.
- ou -
Créez une classe de domaine à l’aide de l’outil Classe de domaine nommée.
Cet outil crée une classe qui possède une propriété de domaine nommée Name. Les propriétés Is Element Name et Is Moniker Key de cette propriété de domaine sont initialisées à la valeur
true
.- ou -
Créez une relation d’héritage de la classe de domaine vers une autre classe possédant une propriété de clé de 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 propriété de clé. Dans le cas, par exemple, d’une définition DSL comportant une classe Person qui possède une propriété Name, l’utilisateur peut définir une valeur Name identique pour deux éléments. Bien que le modèle puisse être enregistré dans le fichier, il ne serait pas rechargé correctement.
Plusieurs méthodes permettent d’éviter cette situation :
Définissez Is Element Name =
true
de la propriété de domaine de clé. Sélectionnez la propriété de domaine dans le diagramme Définition DSL, puis choisissez sa 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 consiste à ajouter un chiffre à la fin du nom de la 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 définition DSL. Dans l’Explorateur DSL, sélectionnez Editor\Validation, puis définissez les propriétés Utilise… sur
true
.Il existe une méthode de validation générée automatiquement qui vérifie les ambiguïtés. Elle 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 dédié.
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. Prenons par exemple le moniker d’un Album :
<albumMoniker title="/My Favorites/Jazz after Teatime" />
L’une des chansons (Song) de cet Album peut alors être la suivante :
<songMoniker title="/My Favorites/Jazz after Teatime/Hot tea" />
Si toutefois il est fait référence aux Albums par leur ID, 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 en particulier possédera 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é de domaine Title de la classe Album, le nom ou l’identificateur du modèle n’est pas utilisé dans les monikers pour Album et ses enfants incorporés :
<albumMoniker name="Jazz after Teatime" />
<songMoniker title="/Jazz after Teatime/Hot tea" />
Personnalisation de la structure 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 Element Data pour afficher la liste des propriétés et relations issues 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 Use Full Form pour incorporer les nœuds cibles dans des nœuds représentant les instances de relation. Cette option est définie automatiquement lorsque des propriétés de domaine sont ajoutées à 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 plutôt qu’en tant que 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 Element Data, puis utilisez les commandes de menu Monter et Descendre.
Personnalisation majeure à l’aide du code du programme
Vous pouvez remplacer une partie ou la totalité des algorithmes de sérialisation.
Nous vous recommandons d’étudier le code qui se trouve dans Dsl\Generated Code\Serializer.cs et SerializationHelper.cs.
Personnalisation de la sérialisation d’une classe en particulier
Définissez Is Custom dans le nœud de cette classe sous Xml Serialization Behavior.
Transformez tous les modèles, générez la solution et examinez les erreurs de compilation qui en résultent. Les commentaires situés à côté de chaque erreur expliquent le code à fournir.
Spécification d’une sérialisation personnalisée pour l’ensemble du modèle
- 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 SerializationHelper
classe ou implémenter une TypeConverter
capacité de conversion de chaque type de données personnalisé vers 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 qui utilisaient BinaryFormatter
la sérialisation, vous pouvez implémenter une TypeConverter
désérialisation des 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 de Xml Serialization Behavior
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 la liste des propriétés et relations sources figurant sur cet élément. Les relations sont représentées à la fois en tant que telles et sous leurs classes sources.
Le tableau suivant récapitule les options disponibles 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.
Xml Class data
Ces éléments se trouvent dans l’Explorateur DSL sous Xml Serialization Behavior\Class Data.
Propriété | Description |
---|---|
Has Custom Element Schema | Si la valeur est true, indique que la classe de domaine possède un schéma d’élément personnalisé. |
Is Custom | Définissez la valeur 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 obtenir 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 de nœud XML des éléments de cette classe. La valeur par défaut est une version minuscule du nom de la classe de domaine. |
Nom de l’attribut du moniker | Nom de l’attribut utilisé dans les éléments du moniker pour contenir la référence. Si vide, le nom de la propriété ou l'identificateur de clé est utilisé. Dans cet exemple, il s’agit de « name » : <personMoniker name="/Mike Nash"/> |
Nom de l’élément du 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 la classe avec le suffixe « Moniker ». Par exemple : personMoniker . |
Nom du type de moniker | Nom du type XSD généré pour les monikers aux éléments de cette classe. Le XSD se trouve dans Dsl\Generated Code\*Schema.xsd. |
Serialize Id | Si la valeur est true, indique que le GUID de l’élément est inclus dans le fichier. La valeur doit être définie sur True s’il n’existe aucune propriété marquée Est Moniker Key et la DSL définit les relations de référence à cette classe. |
Nom de type | Nom du type XML généré dans XSD à partir de la classe de domaine indiquée. |
Notes | Notes informelles associées à cet élément. |
Données des propriétés 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 Attribute, la propriété est sérialisée en tant qu’attribut xml ; si la valeur est définie sur Element, 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 ou l'élément XML 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 | Si la valeur est true, indique que vous souhaitez fournir votre propre code pour générer et résoudre les monikers qui traversent 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. |
Omit Element | Si la valeur est true, indique que la balise XML correspondant au rôle source est omise dans le 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. |
Use Full Form | Si la valeur est true, indique que chaque élément ou moniker cible est placé dans un nœud XML représentant la relation. Cette propriété doit être true si la relation possède ses propres propriétés de domaine. |