Anpassa fillagring och XML-serialisering

När användaren sparar en instans, eller modell, av ett domänspecifikt språk (DSL) i Visual Studio, skapas eller uppdateras en XML-fil. Filen kan laddas om för att återskapa modellen i butiken.

Du kan anpassa serialiseringsschemat genom att justera inställningarna under XML-serialiseringsbeteende i DSL Explorer. Det finns en nod under XML-serialiseringsbeteende för varje domänklass, egenskap och relation. Relationerna finns under deras källklasser. Det finns också noder som motsvarar form-, kopplings- och diagramklasserna.

Du kan också skriva programkod för mer avancerad anpassning.

Notera

Om du vill spara modellen i ett visst format, men du inte behöver läsa in den igen från formuläret, bör du överväga att använda textmallar för att generera utdata från modellen i stället för ett anpassat serialiseringsschema. Mer information finns i generera kod från ett Domain-Specific-språk.

Modell- och diagramfiler

Varje modell sparas i två filer:

  • Modellfilen har ett namn som Model1.mydsl. Den lagrar modellelementen och relationerna och deras egenskaper. Filnamnstillägget, till exempel .mydsl, bestäms av egenskapen FileExtension för noden Editor i DSL-definitionen.

  • Diagramfilen har ett namn som Model1.mydsl.diagram. Den lagrar former, kopplingar och deras positioner, färger, linjetjocklekar och annan information om diagrammets utseende. Om användaren tar bort en .diagram fil går inte den viktiga informationen i modellen förlorad. Endast diagrammets layout går förlorad. När modellfilen öppnas skapas en standarduppsättning former och kopplingar.

Så här ändrar du filnamnstillägget för en DSL

  1. Öppna DSL-definitionen. I DSL Explorer klickar du på noden Redigerare.

  2. I fönstret Egenskaper redigerar du egenskapen FileExtension. Ta inte med den inledande . för filnamnstillägget.

  3. I Solution Explorer ändrar du namnet på de två objektmallfilerna i DslPackage\ProjectItemTemplates. Dessa filer har namn som följer det här formatet:

    myDsl.diagram

    myDsl.myDsl

Standard serialiseringsschemat

För att skapa ett exempel för det här avsnittet användes följande DSL-definition.

DSL-definitionsdiagram – familjeträdsmodell

Denna DSL användes för att skapa en modell som har följande utseende på skärmen.

Träddiagram, verktygslåda och utforskare

Den här modellen sparades och öppnades sedan igen i XML-textredigeraren:

<?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>

Observera följande punkter om den serialiserade modellen:

  • Varje XML-nod har ett namn som är samma som ett domänklassnamn, förutom att den första bokstaven är gemen. Till exempel familyTreeModel och person.

  • Domänegenskaper som Namn och BirthYear serialiseras som attribut i XML-noderna. Återigen konverteras första tecknet i egenskapsnamnet till gemener.

  • Varje relation serialiseras som en XML-nod kapslad i relationens källslut. Noden har samma namn som egenskapen för källroll, men med en inledande liten bokstav.

    I DSL-definitionen hämtas till exempel en roll med namnet People i klassen FamilyTree. I XML-koden representeras rollen Personer med en nod med namnet people kapslad i noden familyTreeModel.

  • Målet för varje inbäddningsrelation serialiseras som en nod inbäddad under relationen. Till exempel innehåller noden people flera person noder.

  • Måländen av varje referensrelation serialiseras som en moniker, som kodar en referens till målelementet.

    Under en person nod kan det till exempel finnas en children relation. Den här noden innehåller monikers som:

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

Förstå Monikers

Monikers används för att representera korsreferenser mellan olika delar av modellen och diagramfilerna. De används också i .diagram-filen för att referera till noder i modellfilen. Det finns två former av moniker:

  • ID-monikers citerar GUID för målelementet. Till exempel:

    <personShapeMoniker Id="f79734c0-3da1-4d72-9514-848fa9e75157" />
    
  • Kvalificerade nyckelmonikers identifierar målelementet med värdet för en utsedd domänegenskap som kallas monikernyckeln. Monikern för målelementet är prefix med monikern för dess överordnade element i trädet för inbäddningsrelationer.

    Följande exempel är hämtade från en DSL där det finns en domänklass med namnet Album, som har en inbäddningsrelation till en domänklass med namnet Song:

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

    Kvalificerade nyckelmonikers används om målklassen har en domänegenskap där alternativet Är Moniker-nyckel är satt till true i XML-serialiseringsbeteende. I exemplet anges det här alternativet för domänegenskaper med namnet "Title" i domänklasserna "Album" och "Song".

Kvalificerade nyckelbeteckningar är lättare att läsa än ID-beteckningar. Om du vill att XML:en för dina modellfiler ska vara läsbar för människor bör du överväga att använda kvalificerade nyckelmonikers. Det är dock möjligt för användaren att ange att fler än ett element ska ha samma monikernyckel. Duplicerade nycklar kan leda till att filen inte läses in på rätt sätt. Om du definierar en domänklass som refereras med hjälp av kvalificerade nyckelmonikers bör du därför överväga olika sätt att förhindra att användaren sparar en fil med duplicerade monikers.

Ställ in en domänklass som ska refereras med ID-märken

  1. Kontrollera att Är Moniker-nyckel är false för varje domänegenskap i klassen och dess basklasser.

    1. I DSL Explorer expanderar du Xml Serialization Behavior\Class Data\<domänklassen>\Element Data.

    2. Kontrollera att Är Moniker-nyckel är false för varje domänegenskap.

    3. Om domänklassen har en basklass upprepar du proceduren i den klassen.

  2. Ange Serialisera ID = true för domänklassen.

    Den här egenskapen finns under XML-serialiseringsbeteende.

Ange en domänklass som ska refereras av kvalificerade nyckelmonikers

  • Ange Är Moniker-nyckel för en domänegenskap för en befintlig domänklass. Egenskapens typ måste vara string.

    1. I DSL Explorer expanderar du Xml Serialization Behavior\Class Data\<domänklassen>\Element Dataoch väljer sedan domänegenskapen.

    2. I fönstret Egenskaper anger du Är Moniker-nyckel till true.

  • -eller-

    Skapa en ny domänklass med hjälp av verktyget Named Domain Class.

    Det här verktyget skapar en ny klass som har en domänegenskap med namnet Namn. Egenskaperna Is Element Name och Is Moniker Key för den här domänegenskapen initieras till true.

  • -eller-

    Skapa en arvsrelation från domänklassen till en annan klass som har en monikernyckelegenskap.

Undvik duplicerade Monikers

Om du använder kvalificerade nyckelbenämningar kan det hända att två element i en användares modell får samma värde i nyckelegenskapen. Om din DSL till exempel har en klassperson som har ett egenskapsnamn, kan användaren ange att Namnen på två element ska vara samma. Även om modellen kunde sparas i en fil skulle den inte läsas in korrekt på nytt.

Det finns flera metoder som hjälper dig att undvika den här situationen:

  • Ange som elementnamn = true för nyckeldomänegenskapen. Välj domänegenskapen i DSL-definitionsdiagrammet och ange sedan värdet i fönstret Egenskaper.

    När användaren skapar en ny instans av klassen tilldelas domänegenskapen automatiskt ett annat värde. Standardbeteendet lägger till ett tal i slutet av klassnamnet. Detta hindrar inte användaren från att ändra namnet till en dubblett, men det hjälper i de fall där användaren inte har angett värdet innan modellen sparas.

  • Aktivera validering för DSL. I DSL Explorer väljer du Redigerare\Validering och anger egenskaperna Använder... till true.

    Det finns en automatiskt genererad valideringsmetod som söker efter tvetydigheter. Metoden finns i Load valideringskategori. Detta säkerställer att användaren får en varning om att det kanske inte går att öppna filen igen.

    Mer information finns i validering i ett Domain-Specific språk.

Moniker-vägar och -kval

En kvalificerad nyckelmoniker slutar med monikernyckeln och föregås av monikern för dess överordnade i det inbäddade trädet. Om monikern för ett album till exempel är:

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

Sedan kan en av låtarna i det albumet vara:

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

Om album istället refereras till genom ID skulle beteckningarna vara följande:

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

Observera att eftersom ett GUID är unikt föregås det aldrig av monikern för dess överordnade.

Om du vet att en viss domänegenskap alltid har ett unikt värde i en modell kan du ange Är Moniker-kvalificerare till true för den egenskapen. Detta gör att den används som en kvalificerare, utan att använda det överordnade objektets moniker. Om du till exempel anger både Is Moniker Qualifier och Is Moniker Key för domeinegenskapen Title i klassen Album, används inte modellens namn eller identifierare i moniklar för Album och dess inbäddade element.

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

Anpassa XML-strukturen

Om du vill göra följande anpassningar expanderar du XML-serialiseringsbeteendet noden i DSL Explorer. Under en domänklass expanderar du noden Elementdata för att se listan över egenskaper och relationer som hämtas i den här klassen. Välj en relation och justera dess alternativ i fönstret Egenskaper.

  • Ange Utelämna element till sant för att utelämna källrollnoden och lämna bara listan över målelement. Du bör inte ange det här alternativet om det finns fler än en relation mellan käll- och målklasserna.

    <familyTreeModel ...>
      <!-- The following node is omitted by using Omit Element: -->
      <!-- <people> -->
        <person name="Henry VIII" .../>
        <person name="Elizabeth I" .../>
      <!-- </people> -->
    </familyTreeModel>
    
  • Ange Använd fullständigt formulär för att bädda in målnoderna i noder som representerar relationsinstanserna. Det här alternativet anges automatiskt när du lägger till domänegenskaper i en domänrelation.

    <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>
    
  • Ange Representation = Element så att en domänegenskap sparas som ett element i stället för som ett attributvärde.

    <person name="Elizabeth I" birthYear="1533">
      <deathYear>1603</deathYear>
    </person>
    
  • Om du vill ändra i vilken ordning attribut och relationer serialiseras högerklickar du på ett objekt under Elementdata och använder kommandona Flytta upp eller Flytta ned meny.

Större anpassning med programkod

Du kan ersätta delar eller alla serialiseringsalgoritmer.

Vi rekommenderar att du studerar koden i Dsl\Generated Code\Serializer.cs och SerializationHelper.cs.

Så här anpassar du serialiseringen av en viss klass

  1. Ange är anpassat i noden för klassen under XML-serialiseringsbeteende.

  2. Transformera alla mallar, skapa lösningen och undersöka de resulterande kompileringsfelen. Kommentarer nära varje fel förklarar vilken kod du måste ange.

För att tillhandahålla din egen serialisering för hela modellen

  1. Åsidosätt metoder i Dsl\GeneratedCode\SerializationHelper.cs

Obs

Från och med Visual Studio 2022 17.13 stöder standard-serialiseringsimplementeringen inte längre serialisering eller deserialisering av anpassade datatyper med BinaryFormatter på grund av säkerhetsrisker med BinaryFormatter.

Om du använder en anpassad datatyp för domänegenskaper måste du antingen åsidosätta serialiseringsmetoderna i klassen SerializationHelper eller implementera en TypeConverter som kan konvertera varje anpassad datatyp till och från en sträng.

Vi rekommenderar inte att du använder BinaryFormatter av säkerhetsskäl, men om du måste upprätthålla bakåtkompatibilitet med äldre modeller som använde BinaryFormatter serialisering kan du implementera en TypeConverter som deserialiserar binära data. Följande kodfragment fungerar som en mall för att implementera den här kompatibiliteten:

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
{
    // ...
}

Alternativ i XML-serialiseringsbeteende

I DSL Explorer innehåller noden Xml Serialization Behavior en underordnad nod för varje domänklass, relationsklass, form, koppling och diagramklass. Under var och en av dessa noder finns en lista över egenskaper och relationer som kommer från det elementet. Relationer representeras både i sin egen rätt och under sina källklasser.

I följande tabell sammanfattas de alternativ som du kan ange i det här avsnittet i DSL-definitionen. I varje fall väljer du ett element i DSL Explorer och anger alternativen i fönstret Egenskaper.

Xml-klassdata

Dessa element finns i DSL Explorer under Xml Serialization Behavior\Class Data.

Egenskap Beskrivning
Har anpassat elementschema Om sant anger att domänklassen har ett anpassat elementschema
Är anpassad Ange värdet till True om du vill skriva din egen serialiserings- och deserialiseringskod för den här domänklassen.

Skapa lösningen och undersöka felen för att identifiera detaljerade instruktioner.
Domänklass Domänklass som den här klassdatanoden gäller för. Skrivskyddad.
Elementnamn Xml-nodnamn för element i den här klassen. Standardvärdet är en lägre version av domännamnet för domänklassen.
Namn på Moniker-attribut Namnet på attributet som används i moniker-element för att innehålla referensen. Om det är tomt används namnet på nyckelattributet eller ID:t.

I det här exemplet är det "name": <personMoniker name="/Mike Nash"/>
Moniker-elementnamn Namnet på xml-elementet som används för monikers som refererar till element i den här klassen.

Standardvärdet är en gemen version av klassnamnet med suffixet "Moniker". Till exempel personMoniker.
Namn på Moniker-typ Namnet på den xsd-typ som genererats för identifierare till element i den här klassen. XSD finns i Dsl\Generated Code\*Schema.xsd
Serialisera identifikator Om sant ingår elementets GUID i filen. Värdet måste anges till True om det inte finns någon egenskap som är markerad Är Moniker Key och DSL definierar referensrelationer till den här klassen.
Typnamn Namnet på xml-typen som genereras i xsd från den avsedda domänklassen.
Anteckningar Informella anteckningar som är associerade med det här elementet

Xml-egenskapsdata

Xml-egenskapsnoder finns under klassnoderna.

Egenskap Beskrivning
Domänegenskap Egenskap som xml-serialiseringskonfigurationsdata gäller för. Skrivskyddad.
Är Moniker-nyckel Om värdet är inställt på Trueanvänds egenskapen som nyckel för att skapa monikers som refererar till instanser av den här domänklassen.
Är Moniker-kvalificerare Om värdet är inställt på Trueanvänds egenskapen för att skapa kvalificeraren i moniker. Om falskt, och om SerializeId inte är sann för den här domänklassen, bestäms monikers av det överordnade elementets moniker i inbäddningsträdet.
Representation Om värdet är inställt på Attributeserialiseras egenskapen som ett XML-attribut. om värdet är inställt på Elementserialiseras det som ett element. Om värdet är inställt på Ignorera, är det inte serialiserat.
Xml-namn Namn som används för xml-attributet eller elementet som representerar egenskapen. Som standard är värdet en gemen version av domännamnet.
Anteckningar Informella anteckningar som är associerade med det här elementet

Xml-rolldata

Rolldatanoder finns under källklassnoderna.

Egenskap Beskrivning
Har anpassad Moniker Ställ in detta på sant om du vill tillhandahålla din egen kod för att generera och lösa moniker som genomgår den här relationen.

Detaljerade instruktioner finns i skapa lösningen och dubbelklicka sedan på felmeddelandena.
Domänrelation Anger den relation som dessa alternativ gäller för. Skrivskyddad.
Utelämna element Om det är sant utelämnas XML-noden som motsvarar källrollen från schemat.

Om det finns mer än en relation mellan käll- och målklasserna skiljer den här rollnoden mellan länkar som tillhör de två relationerna. Vi rekommenderar därför att du inte anger det här alternativet i det här fallet.
Namn på rollelement Anger namnet på XML-elementet som härleds från källrollen. Standardvärdet är namnet på rollegenskapen.
Använd fullständigt formulär Om det är sant omges varje målelement eller moniker av en XML-nod som representerar relationen. Detta bör anges till sant om relationen har sina egna domänegenskaper.