Personalizzare l'archiviazione file e la serializzazione XML
Quando l'utente salva un'istanza o modello, di un linguaggio specifico del dominio in Visual Studio, viene creato o aggiornato un file XML. Il file può essere ricaricato per ricreare il modello nello Store.
È possibile personalizzare lo schema di serializzazione modificando le impostazioni in Comportamento di serializzazione Xml in Esplora DSL. Esiste un nodo in Comportamento di serializzazione XML per ogni classe di dominio, proprietà e relazione. Le relazioni si trovano sotto le relative classi di origine. Sono inoltre presenti nodi corrispondenti alle classi shape, connector e diagram.
È anche possibile scrivere codice programma per una personalizzazione più avanzata.
Nota
Se si desidera salvare il modello in un formato specifico, ma non è necessario ricaricarlo da tale modulo, è consigliabile usare modelli di testo per generare l'output dal modello, anziché uno schema di serializzazione personalizzato. Per ulteriori informazioni, vedere Generazione di codice da un Domain-Specific Linguaggio.
File di modello e diagramma
Ogni modello viene salvato in due file:
Il file del modello ha un nome, ad esempio
Model1.mydsl
. Archivia gli elementi e le relazioni del modello e le relative proprietà. L'estensione di file, ad esempio.mydsl
, è determinata dalla proprietà FileExtension del nodo Editor nella definizione DSL.Il file del diagramma ha un nome, ad esempio
Model1.mydsl.diagram
. Archivia le forme, i connettori e le relative posizioni, colori, spessori linea e altri dettagli sull'aspetto del diagramma. Se l'utente elimina un file di.diagram
, le informazioni essenziali nel modello non andranno perse. Solo il layout del diagramma viene perso. Quando il file del modello viene aperto, viene creato un set predefinito di forme e connettori.
Per modificare l'estensione di un file DSL
Aprire la definizione DSL. In Esplora DSL fare clic sul nodo Editor.
Nella finestra Proprietà modificare la proprietà FileExtension. Non includere il
.
iniziale dell'estensione del nome file.In Esplora soluzioni, modifica il nome dei due file modello di elemento in DslPackage\ProjectItemTemplates. Questi file hanno nomi che seguono questo formato:
myDsl.diagram
myDsl.myDsl
Schema di serializzazione predefinito
Per creare un esempio per questo argomento, è stata usata la definizione DSL seguente.
Diagramma della definizione DSL
Questo linguaggio DSL è stato usato per creare un modello con l'aspetto seguente sullo schermo.
Questo modello è stato salvato e quindi riaperto nell'editor di testo 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>
Si notino i punti seguenti sul modello serializzato:
Ogni nodo XML ha un nome identico a quello di un nome di classe di dominio, ad eccezione del fatto che la lettera iniziale è minuscola. Ad esempio,
familyTreeModel
eperson
.Le proprietà di dominio, ad esempio Name e BirthYear, vengono serializzate come attributi nei nodi XML. Anche in questo caso, il carattere iniziale del nome della proprietà viene convertito in lettere minuscole.
Ogni relazione viene serializzata come nodo XML annidato all'interno della fine della relazione di origine. Il nodo ha lo stesso nome della proprietà del ruolo di origine, ma con un carattere iniziale minuscolo.
Ad esempio, nella definizione DSL, un ruolo denominato People viene originato nella classe FamilyTree. Nel codice XML il ruolo People viene rappresentato con un nodo denominato
people
annidato all'interno del nodofamilyTreeModel
.La fine di destinazione di ogni relazione di incorporamento viene serializzata come nodo annidato nella relazione. Ad esempio, il nodo
people
contiene diversi nodiperson
.La fine di ogni relazione di riferimento viene serializzata come moniker, che codifica un riferimento all'elemento di destinazione.
Ad esempio, in un nodo
person
può esistere una relazionechildren
. Questo nodo contiene moniker come:<personMoniker name="/f817b728-e920-458e-bb99-98edc469d78f/Elizabeth I" />
Informazioni sui moniker
I moniker vengono usati per rappresentare i riferimenti incrociati tra parti diverse del modello e dei file di diagramma. Vengono usati anche nel file .diagram
per fare riferimento ai nodi nel file del modello. Esistono due forme di moniker:
L'ID moniker indica il GUID dell'elemento di destinazione. Per esempio:
<personShapeMoniker Id="f79734c0-3da1-4d72-9514-848fa9e75157" />
moniker chiave qualificati identificare l'elemento di destinazione in base al valore di una proprietà di dominio designata denominata chiave moniker. Il moniker dell'elemento di destinazione è preceduto dal moniker del relativo elemento padre nell'albero delle relazioni di incorporamento.
Gli esempi seguenti sono tratti da un linguaggio DSL in cui è presente una classe di dominio denominata Album, che ha una relazione di incorporamento a una classe di dominio denominata Song:
<albumMoniker title="/My Favorites/Jazz after Teatime" /> <songMoniker title="/My Favorites/Jazz after Teatime/Hot tea" />
I moni ker chiave qualificati vengono utilizzati se la classe di destinazione dispone di una proprietà di dominio per cui l'opzione chiave moniker è impostata su
true
in comportamento di serializzazione XML. Nell'esempio questa opzione viene impostata per le proprietà di dominio denominate "Title" nelle classi di dominio "Album" e "Song".
I moniker chiave qualificati sono più facili da leggere rispetto ai moniker ID. Se si prevede che il codice XML dei file di modello sia leggibile dall'utente, è consigliabile usare moniker chiave qualificati. Tuttavia, è possibile che l'utente imposti più di un elemento con la stessa chiave moniker. Le chiavi duplicate potrebbero impedire il corretto ricaricamento del file. Pertanto, se si definisce una classe di dominio a cui viene fatto riferimento usando moniker chiave qualificati, è consigliabile prendere in considerazione modi per impedire all'utente di salvare un file con moniker duplicati.
Per impostare una classe di dominio a cui fare riferimento tramite moniker ID
Assicurarsi che sia la Chiave Moniker
false
per ogni proprietà di dominio nella classe e nelle relative classi di base.In Esplora DSL espandi Comportamento di serializzazione Xml\Class Data\<classe di dominio>\Element Data.
Verificare che sia la chiave moniker per ogni proprietà di dominio sia
false
.Se la classe di dominio ha una classe base, ripetere la routine in tale classe.
Impostare ID serializzato =
true
per la classe di dominio.Questa proprietà è disponibile in Comportamento di serializzazione XML.
Per impostare una classe di dominio a cui fare riferimento tramite moniker chiave qualificati
Imposta come chiave moniker per una proprietà di dominio di una classe di dominio esistente. Il tipo della proprietà deve essere
string
.In DSL Explorer, espandi Comportamento di serializzazione Xml\Class Data\<la classe di dominio>\Element Data, e quindi seleziona la proprietà di dominio.
Nella finestra Proprietà, imposta La chiave moniker su
true
.
-o-
Creare una nuova classe di dominio utilizzando lo strumento Classe di Dominio Denominata.
Questo strumento crea una nuova classe con una proprietà di dominio denominata Name. Le proprietà Is Element Name e Is Moniker Key di questa proprietà di dominio vengono inizializzate in
true
.-o-
Creare una relazione di ereditarietà dalla classe di dominio a un'altra classe con una proprietà chiave moniker.
Evitare nomi duplicati
Se si usano moniker chiave qualificati, è possibile che due elementi nel modello di un utente abbiano lo stesso valore nella proprietà chiave. Ad esempio, se il linguaggio DSL ha una classe Person con una proprietà Name, l'utente potrebbe impostare i Nomi di due elementi come uguali. Anche se il modello potrebbe essere salvato nel file, non viene ricaricato correttamente.
Esistono diversi metodi che consentono di evitare questa situazione:
Impostare come nome elemento =
true
per la proprietà del dominio della chiave. Selezionare la proprietà di dominio nel diagramma delle definizioni DSL e quindi impostare il valore nella finestra Proprietà.Quando l'utente crea una nuova istanza della classe , questo valore determina l'assegnazione automatica della proprietà di dominio a un valore diverso. Il comportamento predefinito aggiunge un numero alla fine del nome della classe. Ciò non impedisce all'utente di modificare il nome in un duplicato, ma è utile nel caso in cui l'utente non imposti il valore prima di salvare il modello.
Abilitare la convalida per il linguaggio DSL. In Esploratore DSL selezionare Editor\Validazione e impostare le proprietà Uses... su
true
.Esiste un metodo di convalida generato automaticamente che verifica la presenza di ambiguità. Il metodo si trova nella categoria di convalida
Load
. In questo modo si assicura che l'utente venga avvisato che potrebbe non essere possibile riaprire il file.Per altre informazioni, vedere Validation in a Domain-Specific Language.
Percorsi e qualificatori di moniker
Un moniker di chiave qualificato termina con la chiave del moniker ed è preceduto dal moniker del relativo elemento padre nell'albero di incorporamento. Ad esempio, se il moniker di un album è:
<albumMoniker title="/My Favorites/Jazz after Teatime" />
Poi una delle canzoni in quell'album potrebbe essere:
<songMoniker title="/My Favorites/Jazz after Teatime/Hot tea" />
Tuttavia, se gli album sono referenziati tramite ID, i moniker saranno i seguenti:
<albumMoniker Id="77472c3a-9bf9-4085-976a-d97a4745237c" />
<songMoniker title="/77472c3a-9bf9-4085-976a-d97a4745237c/Hot tea" />
Si noti che poiché un GUID è univoco, non è mai preceduto dal moniker del relativo padre.
Se si sa che una determinata proprietà di dominio avrà sempre un valore univoco all'interno di un modello, è possibile impostare Qualificatore Moniker su true
per tale proprietà. In questo modo viene usato come qualificatore, senza usare il moniker del genitore. Ad esempio, se si impostano sia Is Moniker Qualifier che Is Moniker Key per la proprietà di dominio Title della classe Album, il nome o l'identificatore del modello non viene utilizzato nei moniker per Album e i suoi figli incorporati:
<albumMoniker name="Jazz after Teatime" />
<songMoniker title="/Jazz after Teatime/Hot tea" />
Personalizzare la struttura del codice XML
Espandere il nodo Comportamento di serializzazione XML in Esplora DSL per apportare le personalizzazioni seguenti. In una classe di dominio espandere il nodo Dati elemento per visualizzare l'elenco delle proprietà e delle relazioni che vengono generate in questa classe. Selezionare una relazione e modificarne le opzioni nella finestra Proprietà.
Impostare Omit Element su true per omettere il nodo del ruolo di origine, lasciando solo l'elenco degli elementi di destinazione. Questa opzione non deve essere impostata se sono presenti più relazioni tra le classi di origine e di destinazione.
<familyTreeModel ...> <!-- The following node is omitted by using Omit Element: --> <!-- <people> --> <person name="Henry VIII" .../> <person name="Elizabeth I" .../> <!-- </people> --> </familyTreeModel>
Impostare Usa modulo completo per incorporare i nodi di destinazione nei nodi che rappresentano le istanze della relazione. Questa opzione viene impostata automaticamente quando si aggiungono proprietà di dominio a una relazione di dominio.
<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>
Impostare Rappresentazione = Elemento per salvare una proprietà di dominio come elemento anziché come valore dell'attributo.
<person name="Elizabeth I" birthYear="1533"> <deathYear>1603</deathYear> </person>
Per modificare l'ordine in cui vengono serializzati attributi e relazioni, fare clic con il pulsante destro del mouse su un elemento in Dati Elemento e utilizzare i comandi del menu Sposta su o Sposta giù.
Personalizzazione principale con il codice del programma
È possibile sostituire parti o tutti gli algoritmi di serializzazione.
È consigliabile studiare il codice in Dsl\Generated Code\Serializer.cs e SerializationHelper.cs.
Per personalizzare la serializzazione di una determinata classe
Impostare è personalizzato nel nodo per tale classe in Comportamento di serializzazione Xml.
Trasformare tutti i modelli, compilare la soluzione ed esaminare gli errori di compilazione risultanti. I commenti vicino a ogni errore spiegano il codice da fornire.
Per fornire la serializzazione personalizzata per l'intero modello
- Effettuare l'override dei metodi in Dsl\GeneratedCode\SerializationHelper.cs
Nota
A partire da Visual Studio 2022 17.13, l'implementazione di serializzazione predefinita non supporta più la serializzazione o la deserializzazione dei tipi di dati personalizzati usando BinaryFormatter a causa di rischi di sicurezza con BinaryFormatter.
Se si usa un tipo di dati personalizzato per qualsiasi proprietà di dominio, è necessario eseguire l'override dei metodi di serializzazione nella classe SerializationHelper
oppure implementare un TypeConverter
in grado di convertire ogni tipo di dati personalizzato in e da una stringa.
Sebbene non sia consigliabile usare BinaryFormatter
per motivi di sicurezza, se è necessario mantenere la compatibilità con le versioni precedenti con i modelli meno recenti usati BinaryFormatter
serializzazione, è possibile implementare un TypeConverter
che deserializza i dati binari. Il frammento di codice seguente funge da modello per implementare questa 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
{
// ...
}
Opzioni nel comportamento di serializzazione XML
In Esplora DSL, il nodo relativo al Comportamento di serializzazione XML contiene un nodo figlio per ogni classe di dominio, relazione, forma, connettore e classe di diagramma. In ognuno di questi nodi è riportato un elenco di proprietà e relazioni originate in tale elemento. Le relazioni sono rappresentate sia autonomamente sia nelle loro classi di origine.
La tabella seguente riepiloga le opzioni che è possibile impostare in questa sezione della definizione DSL. In ogni caso, selezionare un elemento in Esplora DSL e impostare le opzioni nella finestra Proprietà.
Dati della classe Xml
Questi elementi sono reperibili in DSL Explorer sotto Comportamento di serializzazione XML\Dati di classe.
Proprietà | Descrizione |
---|---|
Ha uno schema di elemento personalizzato | Se True, indica che la classe di dominio ha uno schema di elemento personalizzato |
È personalizzato | Impostare il valore su True se si desidera scrivere codice di serializzazione e deserializzazione personalizzato per questa classe di dominio. Compilare la soluzione ed esaminare gli errori per individuare istruzioni dettagliate. |
Classe Dominio | Classe di dominio a cui si applica questo nodo dati della classe. Sola lettura. |
Nome dell'elemento | Nome del nodo XML per gli elementi di questa classe. Il valore predefinito è una versione minuscola del nome della classe di dominio. |
Nome attributo moniker | Nome dell'attributo utilizzato negli elementi moniker per contenere il riferimento. Se è vuoto, viene usato il nome della proprietà o dell'ID della chiave. In questo esempio è "name": <personMoniker name="/Mike Nash"/> |
Nome dell'elemento Moniker | Nome dell'elemento xml utilizzato per i moniker che fanno riferimento agli elementi di questa classe. Il valore predefinito è una versione minuscola del nome della classe suffisso con "Moniker". Ad esempio, personMoniker . |
Nome tipo moniker | Nome del tipo xsd generato per i moniker degli elementi di questa classe. XSD si trova in Dsl\Generated Code\*Schema.xsd |
Serializzare l'ID | Se True, il GUID dell'elemento viene incluso nel file. Il valore deve essere impostato su True se non è presente alcuna proprietà contrassegnata Is Moniker Key e il linguaggio DSL definisce le relazioni di riferimento a questa classe. |
Nome del tipo | Nome del tipo xml generato nella classe xsd dalla classe di dominio designata. |
Note | Note informali associate a questo elemento |
Dati delle proprietà Xml
I nodi della proprietà Xml si trovano nei nodi della classe.
Proprietà | Descrizione |
---|---|
Proprietà del dominio | Proprietà a cui si applicano i dati di configurazione della serializzazione xml. Sola lettura. |
Chiave Moniker | Se il valore è impostato su True, la proprietà viene usata come chiave per la creazione di moniker che fanno riferimento a istanze di questa classe di dominio. |
Qualificatore Moniker | Se il valore è impostato su True, la proprietà viene utilizzata per la creazione del qualificatore nei moniker. Se false e se SerializeId non è true per questa classe di dominio, i moniker sono qualificati dal moniker dell'elemento padre nell'albero di incorporamento. |
Rappresentazione | Se il valore è impostato su Attributo, la proprietà viene serializzata come attributo xml; se il valore è impostato su Element, viene serializzato come elemento; se il valore è impostato su Ignora, non viene serializzato. |
Nome XML | Nome utilizzato per l'attributo o l'elemento xml che rappresenta la proprietà . Per impostazione predefinita, il valore è una versione minuscola del nome della proprietà di dominio. |
Note | Note informali associate a questo elemento |
Dati del ruolo XML
I nodi di dati di ruolo si trovano sotto i nodi della classe sorgente.
Proprietà | Descrizione |
---|---|
Ha moniker personalizzato | Impostare questo valore su true se si vuole fornire codice personalizzato per la generazione e la risoluzione dei moniker che attraversano questa relazione. Per istruzioni dettagliate, compilare la soluzione e quindi fare doppio clic sui messaggi di errore. |
Relazione di dominio | Specifica la relazione a cui si applicano queste opzioni. Sola lettura. |
Ometti Elemento | Se true, il nodo XML corrispondente al ruolo di origine viene omesso dallo schema. Se sono presenti più relazioni tra le classi di origine e di destinazione, questo nodo del ruolo distingue tra i collegamenti che appartengono alle due relazioni. In questo caso, è consigliabile non impostare questa opzione. |
Nome dell'elemento ruolo | Specifica il nome dell'elemento XML derivato dal ruolo di origine. Il valore predefinito è il nome della proprietà del ruolo. |
Usa modulo completo | Se true, ogni elemento o moniker di destinazione è racchiuso in un nodo XML che rappresenta la relazione. Questa proprietà deve essere impostata su true se la relazione ha proprietà di dominio specifiche. |