Condividi tramite


Personalizzare l'archiviazione dei file e la serializzazione XML

Quando l'utente salva un'istanza o un 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 altre informazioni, vedere Generazione di codice da un linguaggio specifico del dominio.

File di modello e diagramma

Ogni modello viene salvato in due file:

  • Il file del modello ha un nome, Model1.mydslad esempio . Archivia gli elementi e le relazioni del modello e le relative proprietà. L'estensione di file, .mydsl ad esempio, è determinata dalla proprietà FileExtension del nodo Editor nella definizione DSL.

  • Il file del diagramma ha un nome, Model1.mydsl.diagramad esempio . Archivia le forme, i connettori e le relative posizioni, colori, spessori linea e altri dettagli sull'aspetto del diagramma. Se l'utente elimina un .diagram file, 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 linguaggio DSL

  1. Aprire la definizione DSL. In Esplora DSL fare clic sul nodo Editor.

  2. Nella Finestra Proprietà modificare la proprietà FileExtension. Non includere l'iniziale . dell'estensione del nome file.

  3. In Esplora soluzioni modificare 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 delle definizioni DSL - Modello ad albero di famiglia

Questo linguaggio DSL è stato usato per creare un modello con l'aspetto seguente sullo schermo.

Diagramma, casella degli strumenti e finestra di esplorazione dell'albero genealogico

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 e person.

  • 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 familyTreeModel nodo.

  • La fine di destinazione di ogni relazione di incorporamento viene serializzata come nodo annidato nella relazione. Ad esempio, il people nodo contiene diversi person nodi.

  • La fine di destinazione di ogni relazione di riferimento viene serializzata come moniker, che codifica un riferimento all'elemento di destinazione.

    Ad esempio, in un person nodo può esistere una children relazione. 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 .diagram file per fare riferimento ai nodi nel file del modello. Esistono due forme di moniker:

  • I moniker ID virgolette il GUID dell'elemento di destinazione. Ad esempio:

    <personShapeMoniker Id="f79734c0-3da1-4d72-9514-848fa9e75157" />
    
  • I moniker chiave qualificati identificano 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 moniker chiave qualificati vengono utilizzati se la classe di destinazione ha una proprietà di dominio per cui l'opzione Is Moniker Key è 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 causare il caricamento corretto 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

  1. Assicurarsi che Is Moniker Key sia false per ogni proprietà di dominio nella classe e nelle relative classi di base.

    1. In Esplora DSL espandere Comportamento serializzazione XML\Dati classe\classe> dominio<\Dati elemento.

    2. Verificare che Is Moniker Key sia false per ogni proprietà di dominio.

    3. Se la classe di dominio ha una classe base, ripetere la routine in tale classe.

  2. Impostare Serialize ID = 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

  • Impostare Is Moniker Key per una proprietà di dominio di una classe di dominio esistente. Il tipo della proprietà deve essere string.

    1. In Esplora DSL espandere Comportamento serializzazione XML\Dati classe\classe di< dominio>\Dati elemento, quindi selezionare la proprietà di dominio.

    2. Nella Finestra Proprietà impostare Is Moniker Key (Chiave moniker) su .true

  • o

    Creare una nuova classe di dominio usando lo strumento Classe di dominio denominato.

    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 moniker 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 Is Element Name = true per la proprietà del dominio della chiave. Selezionare la proprietà di dominio nel diagramma di definizione 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 Esplora DSL selezionare Editor\Validation 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 Load categoria di convalida. In questo modo si assicura che l'utente venga avvisato che potrebbe non essere possibile riaprire il file.

    Per altre informazioni, vedere Convalida in un linguaggio specifico del dominio.

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 fanno riferimento in base all'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 Is Moniker Qualifier su true per tale proprietà. In questo modo viene usato come qualificatore, senza usare il moniker dell'elemento padre. 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 usato nei moniker per Album e i relativi elementi figlio incorporati:

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

Personalizzare la struttura del codice XML

Per apportare le personalizzazioni seguenti, espandere il nodo Comportamento di serializzazione Xml in Esplora DSL. 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 nel Finestra Proprietà.

  • Impostare Omit Element (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 l'elemento Representation = per fare in modo che una proprietà di dominio sia salvata 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 usare i comandi di 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

  1. Impostare è personalizzato nel nodo per la classe in Comportamento di serializzazione XML.

  2. 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

  1. Eseguire 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 per la 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 SerializationHelper classe oppure implementare un oggetto TypeConverter in grado di convertire ogni tipo di dati personalizzato in e da una stringa.

Anche se non è consigliabile usare BinaryFormatter per motivi di sicurezza, se è necessario mantenere la compatibilità con le versioni precedenti dei modelli meno recenti che utilizzavano BinaryFormatter la serializzazione, è possibile implementare un oggetto 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 Comportamento serializzazione Xml contiene un nodo figlio per ogni classe di dominio, relazione, forma, connettore e classe diagramma. In ognuno di questi nodi è riportato un elenco di proprietà e relazioni originate in tale elemento. Le relazioni sono rappresentate sia nel proprio diritto che nelle relative 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 nel Finestra Proprietà.

Dati della classe Xml

Questi elementi sono disponibili in Esplora DSL in Comportamento serializzazione XML\Dati 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 di dominio Classe di dominio a cui si applica questo nodo dati della classe. Sola lettura.
Nome 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 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 agli elementi di questa classe. XsD è 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 come Is Moniker Key e il linguaggio DSL definisce le relazioni di riferimento a questa classe.
Nome 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
Domain, proprietà 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 utilizzata 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 Attribute, la proprietà viene serializzata come attributo xml; se il valore è impostato su Element, viene serializzato come elemento; se il valore è impostato su Ignore, 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 dati del ruolo sono disponibili nei nodi della classe di origine.

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.
Elemento Omit 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 elemento Role 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.