Compartir a través de


Personalizar el almacenamiento de archivos y la serialización XML

Cuando el usuario guarda una instancia o modelo de un lenguaje específico de dominio (DSL) en Visual Studio, se crea o actualiza un archivo XML. El archivo se puede cargar de nuevo para volver a crear el modelo en Store.

Para personalizar el esquema de serialización, ajuste la configuración en Comportamiento de serialización XML en el Explorador de DSL. Hay un nodo en Comportamiento de serialización xml para cada clase de dominio, propiedad y relación. Las relaciones se encuentran en sus clases de origen. También hay nodos correspondientes a las clases de forma, conector y diagrama.

También puede escribir código de programa para una personalización más avanzada.

Nota:

Si desea guardar el modelo en un formato determinado, pero no necesita volver a cargarlo desde ese formulario, considere la posibilidad de usar plantillas de texto para generar la salida del modelo, en lugar de un esquema de serialización personalizado. Para más información, consulte Generar código a partir de lenguajes específicos de dominio.

Archivos de modelos y diagramas

Cada modelo se guarda en dos archivos:

  • El archivo de modelo tiene un nombre como Model1.mydsl. Almacena los elementos y relaciones del modelo y sus propiedades. La extensión de archivo, como .mydsl , viene determinada por la propiedad FileExtension del nodo Editor en la definición de DSL.

  • El archivo de diagrama tiene un nombre como Model1.mydsl.diagram. Este archivo almacena las formas, los conectores y sus posiciones, colores, grosores de línea y otros detalles de la apariencia del diagrama. Si el usuario elimina un .diagram archivo, no se pierde la información esencial del modelo. Solo se pierde el diseño del diagrama. Cuando se abre el archivo de modelo, se crea un conjunto predeterminado de formas y conectores.

Para cambiar la extensión de archivo de un DSL

  1. Abra la definición de DSL. En el Explorador de DSL, haga clic en el nodo Editor.

  2. En la ventana Propiedades, haga clic en la propiedad FileExtension. No incluya la inicial . de la extensión de nombre de archivo.

  3. En Explorador de soluciones, cambie el nombre de los dos archivos de plantilla de elemento en DslPackage\ProjectItemTemplates. Estos archivos tienen nombres que tienen este formato:

    myDsl.diagram

    myDsl.myDsl

Esquema de serialización predeterminado

Para crear un ejemplo para este tema, se usó la siguiente definición de DSL.

Diagrama de definición DSL - modelo de árbol genealógico

Este DSL se usó para crear un modelo que tenía la siguiente apariencia en la pantalla.

Diagrama de árbol genealógico, cuadro de herramientas y explorador

Este modelo se guardó y, a continuación, se volvió a abrir en el editor de texto 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>

Tenga en cuenta los siguientes puntos sobre el modelo serializado:

  • Cada nodo XML tiene un nombre que es el mismo que un nombre de clase de dominio, excepto que la letra inicial está en minúsculas. Por ejemplo, familyTreeModel y person.

  • Las propiedades de dominio como Name y BirthYear se serializan como atributos en los nodos XML. De nuevo, el carácter inicial del nombre de la propiedad se pone en minúsculas.

  • Cada relación se serializa como un nodo XML anidado dentro del extremo de origen de la relación. El nodo tiene el mismo nombre que la propiedad de rol de origen, pero con un carácter inicial en minúsculas.

    Por ejemplo, en la definición de DSL, se genera un rol denominado Personas en la clase FamilyTree. En el XML, el rol Contactos se representa con un nodo denominado people anidado dentro del familyTreeModel nodo.

  • El extremo de destino de cada relación de inclusión se serializa como un nodo anidado en la relación. Por ejemplo, el nodo people contiene varios nodos person.

  • El extremo de destino de cada relación de referencia se serializa como un moniker, que codifica una referencia al elemento de destino.

    Por ejemplo, en un nodo person, puede haber una relación children. Este nodo contiene monikers como:

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

Descripción de los monikers

Los monikers se usan para representar referencias cruzadas entre las diferentes partes del modelo y los archivos de diagrama. También se usan en el .diagram archivo para hacer referencia a los nodos del archivo de modelo. Hay dos formas de moniker.

  • Monikers de identificador: citan el GUID del elemento de destino. Por ejemplo:

    <personShapeMoniker Id="f79734c0-3da1-4d72-9514-848fa9e75157" />
    
  • Monikers de clave calificados: identifican el elemento de destino por el valor de una propiedad de dominio designada denominada clave de moniker. El moniker del elemento de destino tiene como prefijo el moniker de su elemento primario en el árbol de relaciones de inserción.

    Los ejemplos siguientes se toman de un DSL en el que hay una clase de dominio denominada Album, que tiene una relación de inserción con una clase de dominio denominada Song:

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

    Los monikers de clave calificados se usan si la clase de destino tiene una propiedad de dominio para la que la opción Is Moniker Key está establecida true en en Comportamiento de serialización xml. En el ejemplo, esta opción se establece para las propiedades de dominio denominadas "Title" en las clases de dominio "Álbum" y "Canción".

Los monikers de clave calificados son más fáciles de leer que los monikers de identificador. Si piensa que el XML de los archivos de modelo sea legible, considere la posibilidad de usar monikers de clave completos. Sin embargo, es posible que el usuario establezca más de un elemento para que tenga la misma clave de moniker. Las claves duplicadas podrían hacer que el archivo no se volviera a cargar correctamente. Por lo tanto, si define una clase de dominio a la que se hace referencia mediante monikers de clave calificada, debe considerar formas de impedir que el usuario guarde un archivo que tenga monikers duplicados.

Para establecer que se haga referencia a una clase de dominio mediante monikers de identificador

  1. Asegúrese de que la opción Is Moniker Key es false para cada propiedad de dominio de la clase y sus clases base.

    1. En Explorador de DSL, expanda Comportamiento de serialización XML\Datos de clase\<la clase de dominio>\Datos de elemento.

    2. Compruebe que la opción Is Moniker Key es false para cada propiedad de dominio.

    3. Si la clase de dominio tiene una clase base, repita el procedimiento en esa clase.

  2. Establezca Serialize Id = true para la clase de dominio.

    Esta propiedad se puede encontrar en Comportamiento de serialización XML.

Para establecer una clase de dominio a la que se haga referencia mediante monikers de clave calificados

  • Establezca Is Moniker Key para una propiedad de dominio de una clase de dominio existente. El tipo de propiedad debe ser string.

    1. En Explorador de DSL, expanda Comportamiento de serialización XML\Datos de clase\<la clase de dominio>\Datos de elemento y, a continuación, seleccione la propiedad de dominio.

    2. En la ventana Propiedades, establezca Is Moniker Key en true.

  • O bien

    Cree una nueva clase de dominio mediante la herramienta Clase de dominio con nombre.

    Esta herramienta crea una nueva clase que tiene una propiedad de dominio denominada Nombre. Las propiedades Is Element Name e Is Moniker Key de esta propiedad de dominio se inicializan en true.

  • O bien

    Cree una relación de herencia desde la clase de dominio a otra clase que tenga una propiedad de clave de moniker.

Evitar monikers duplicados

Si usa monikers de clave calificados, es posible que dos elementos del modelo de un usuario puedan tener el mismo valor en la propiedad de clave. Por ejemplo, si el DSL tiene una clase Persona que tiene una propiedad Nombre, el usuario podría establecer los nombres de los dos elementos para que fueran iguales. Aunque el modelo se podría guardar en el archivo, no se volvería a cargar correctamente.

Hay varios métodos que ayudan a evitar esta situación:

  • Establezca Is Element Name = true para la propiedad de dominio de clave. Seleccione la propiedad de dominio en el diagrama de definición de DSL y, a continuación, establezca el valor en la ventana Propiedades.

    Cuando el usuario crea una nueva instancia de la clase, este valor hace que a la propiedad de dominio se le asigne automáticamente un valor diferente. El comportamiento predeterminado agrega un número al final del nombre de clase. Esto no impide que el usuario cambie el nombre a un duplicado, pero ayuda en el caso de que el usuario no establezca el valor antes de guardar el modelo.

  • Habilite la validación del DSL. En el Explorador de DSL, seleccione Editor\Validación y establezca las propiedades Usa... en true.

    Hay un método de validación generado automáticamente que comprueba si hay ambigüedades. El método está en la categoría Load de validación. Esto garantiza que el usuario se avisará de que es posible que no sea posible volver a abrir el archivo.

    Para más información, consulte La validación en los lenguajes específicos de dominio.

Rutas de acceso y calificadores de moniker

Un moniker de clave calificado termina por la clave del moniker y tiene como prefijo el moniker de su elemento primario en el árbol de inserción. Por ejemplo, si el moniker de un álbum es:

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

Una de las canciones de ese álbum podría ser:

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

Sin embargo si, en vez de eso, se hace referencia a los álbumes por identificador, los monikers serían los siguientes:

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

Tenga en cuenta que, dado que un GUID es único, nunca está prefijo por el moniker de su elemento primario.

Si sabe que una propiedad de dominio determinada siempre tendrá un valor único dentro de un modelo, puede establecer Is Moniker Qualifier en true para esa propiedad. Esto hace que se use como calificador, sin usar el moniker del elemento primario. Por ejemplo, si establece Is Moniker Qualifier y Is Moniker Key para la propiedad de dominio Title de la clase Album, el nombre o el identificador del modelo no se usan en monikers para Album y sus elementos secundarios incrustados:

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

Personalización de la estructura del XML

Para realizar las siguientes personalizaciones, expanda el nodo Comportamiento de serialización XML en el Explorador de DSL. En una clase de dominio, expanda el nodo Datos de elemento para ver la lista de propiedades y relaciones que se han creado en esta clase. Seleccione una relación y ajuste sus opciones en la ventana Propiedades.

  • Establezca Omit Element en true para omitir el nodo del rol de origen, dejando solo la lista de elementos de destino. No debe establecer esta opción si hay más de una relación entre las clases de origen y de destino.

    <familyTreeModel ...>
      <!-- The following node is omitted by using Omit Element: -->
      <!-- <people> -->
        <person name="Henry VIII" .../>
        <person name="Elizabeth I" .../>
      <!-- </people> -->
    </familyTreeModel>
    
  • Establezca Use Full Form para insertar los nodos de destino en los nodos que representan las instancias de la relación. Esta opción se establece automáticamente al agregar las propiedades de dominio a una relación de 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>
    
  • Establezca Representación = Elemento para que una propiedad de dominio se guarde como un elemento en lugar de como un valor de atributo.

    <person name="Elizabeth I" birthYear="1533">
      <deathYear>1603</deathYear>
    </person>
    
  • Para cambiar el orden en el que se serializan los atributos y las relaciones, haga clic con el botón derecho en un elemento de Datos de elemento y use los comandos de menú Subir o Bajar.

Personalización importante mediante código de programa

Puede reemplazar parte de los algoritmos de serialización o todos ellos.

Se recomienda que analice el código que se encuentra en Dsl\Generated Code\Serializer.cs y SerializationHelper.cs.

Para personalizar la serialización de una clase determinada

  1. Establezca Is Custom en el nodo para esa clase en Comportamiento de serialización XML.

  2. Transforme todas las plantillas, compile la solución e investigue los errores de compilación resultantes. Los comentarios que aparecen cerca de cada error explican qué código debe proporcionar.

Para proporcionar su propia serialización para todo el modelo

  1. Invalide los métodos de Dsl\GeneratedCode\SerializationHelper.cs

Nota:

A partir de Visual Studio 2022 17.13, la implementación de serialización predeterminada ya no admite la serialización o deserialización de tipos de datos personalizados mediante BinaryFormatter debido a riesgos de seguridad con BinaryFormatter.

Si usa un tipo de datos personalizado para cualquier propiedad de dominio, debe invalidar los métodos de serialización de la SerializationHelper clase o implementar una TypeConverter capacidad para convertir cada tipo de datos personalizado en una cadena y desde ellas.

Aunque no se recomienda usar BinaryFormatter por motivos de seguridad, si debe mantener la compatibilidad con versiones anteriores con modelos anteriores que usaban BinaryFormatter la serialización, puede implementar un TypeConverter que deserialice los datos binarios. El siguiente fragmento de código sirve como plantilla para implementar esta compatibilidad:

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

Opciones de Comportamiento de serialización XML

En el Explorador DSL, el nodo Comportamiento de serialización xml contiene un nodo secundario para cada clase de dominio, relación, forma, conector y clase de diagrama. En cada uno de esos nodos se muestra una lista de propiedades y relaciones con origen en ese elemento. Las relaciones se representan tanto por sí mismas como en sus clases de origen.

En la tabla siguiente se resumen las opciones que puede establecer en esta sección de la definición de DSL. En cada caso, seleccione un elemento en el Explorador de DSL y establezca las opciones en la ventana Propiedades.

Xml Class Data

Estos elementos se encuentran en el Explorador de DSL en Comportamiento de serialización XML\Class Data.

Propiedad Descripción
Has Custom Element Schema Si es True, indica que la clase de dominio tiene un esquema de elemento personalizado.
Is Custom Establezca el valor en True si desea escribir su propio código de serialización y deserialización para esta clase de dominio.

Compile la solución e investigue los errores para encontrar instrucciones detalladas.
Clase de dominio Clase de dominio a la que se aplica este nodo de datos de clase. Solo lectura.
Nombre del elemento Nombre del nodo XML para los elementos de esta clase. El valor predeterminado es una versión en minúsculas del nombre de la clase de dominio.
Moniker Attribute Name Nombre del atributo usado en elementos de moniker para contener la referencia. Si está en blanco, se usa el nombre de la propiedad de clave o el identificador.

En este ejemplo, es "name": <personMoniker name="/Mike Nash"/>
Moniker Element Name Nombre del elemento XML que se usa para los monikers que hacen referencia a los elementos de esta clase.

El valor predeterminado es una versión en minúsculas del nombre de la clase con el sufijo "Moniker". Por ejemplo, personMoniker.
Moniker Type Name Nombre del tipo XSD generado para los monikers para los elementos de esta clase. El XSD está en Dsl\Generated Code\*Schema.xsd
Serialize Id Si es True, el GUID del elemento se incluye en el archivo. El valor debe establecerse en True si no hay ninguna propiedad marcada como Is Moniker Key y el DSL define las relaciones de referencia a esta clase.
Nombre del tipo Nombre del tipo XML generado en el XSD de la clase de dominio designada.
Notas Notas informales asociadas a este elemento

Xml Property Data

Los nodos de propiedad Xml se encuentran en los nodos de clase.

Propiedad Descripción
Propiedad de dominio Propiedad a la que los datos de configuración de serialización de XML se aplican. Solo lectura.
Is Moniker Key Si el valor se establece en True, la propiedad se usa como clave para crear monikers que hagan referencia a instancias de esta clase de dominio.
Is Moniker Qualifier Si el valor se establece en True, la propiedad se usa para crear el calificador en monikers. Si es false y si SerializeId no es true para esta clase de dominio, los monikers se califican mediante el moniker del elemento primario en el árbol de inserción.
Representación Si el valor se establece en Attribute, la propiedad se serializa como un atributo xml; si el valor se establece en Element, se serializa como un elemento; si el valor se establece en Ignore, no se serializa.
Xml Name Nombre utilizado para el atributo o elemento XML que representa la propiedad. De forma predeterminada, el valor es una versión en minúsculas del nombre de propiedad de dominio.
Notas Notas informales asociadas a este elemento

Datos del rol Xml

Los nodos de datos de rol se encuentran en los nodos de clase de origen.

Propiedad Descripción
Has Custom Moniker Establézcalo en true si desea proporcionar su propio código para generar y resolver monikers que recorren esta relación.

Para obtener instrucciones detalladas, compile la solución y, a continuación, haga doble clic en los mensajes de error.
Relación de dominio Especifica la relación a la que se aplican estas opciones. Solo lectura.
Omit Element Si es true, la etiqueta XML correspondiente al rol de origen se omite del esquema.

Si hay más de una relación entre las clases de origen y de destino, este nodo de rol distingue entre los vínculos que pertenecen a las dos relaciones. Por lo tanto, se recomienda no establecer esta opción en este caso.
Role Element Name Especifica el nombre del elemento XML que se deriva del rol de origen. El valor predeterminado es el nombre de la propiedad de rol.
Use Full Form Si es true, cada elemento o moniker de destino se incluye en un nodo XML que representa la relación. Debe establecerse en true si la relación tiene sus propias propiedades de dominio.