Condividi tramite


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

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

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

  3. 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 - modello ad albero genealogico

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

diagramma ad albero genealogico, casella degli strumenti ed esploratore risorse

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

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

  • 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 relazione children. 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

  1. Assicurarsi che sia la Chiave Monikerfalse per ogni proprietà di dominio nella classe e nelle relative classi di base.

    1. In Esplora DSL espandi Comportamento di serializzazione Xml\Class Data\<classe di dominio>\Element Data.

    2. Verificare che sia la chiave moniker per ogni proprietà di dominio sia false.

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

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

    1. In DSL Explorer, espandi Comportamento di serializzazione Xml\Class Data\<la classe di dominio>\Element Data, e quindi seleziona la proprietà di dominio.

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

  1. Impostare è personalizzato nel nodo per tale 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. 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.