Compartir vía


Personalizar almacenamiento de archivos y serialización XML

Cuando el usuario guarda una instancia o modelo, de un lenguaje específico del dominio (DSL) en Visual Studio, se crea o actualiza un archivo XML. El archivo se puede recargar para recrear el modelo en la Tienda.

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 es necesario 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 Generación de código a partir de un lenguaje específico 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. Almacena las formas, conectores y sus posiciones, colores, grosores de línea y otros detalles de la apariencia del diagrama. Si el usuario elimina un archivo .diagram, 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 dsl, haga clic en el nodo Editor.

  2. En la ventana Propiedades, edite la propiedad FileExtension. No incluya el . inicial de la extensión de nombre de archivo.

  3. En el Explorador de soluciones, cambie el nombre de los dos archivos de plantilla de elementos en DslPackage\ProjectItemTemPlates. Estos archivos tienen nombres que siguen 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 de DSL de Diagrama de definición DSL: modelo de árbol genealógico

Este DSL se usó para crear un modelo que tenga 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>

Observe 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 propiedad se convierte 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, un rol denominado People se encuentra en la clase FamilyTree. En el XML, el rol Personas se representa con un nodo denominado people anidado dentro del nodo familyTreeModel.

  • 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 de 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 diferentes partes del modelo y los archivos de diagrama. También se usan en el archivo .diagram 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 identificador del elemento de destino está precedido por el identificador 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 usarán si la clase de destino tiene una propiedad de dominio para la que la opción Is Moniker Key se establece en true 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 "Album" y "Song".

Los monikers de clave calificados son más fáciles de leer que los monikers de identificador. Si quiere que los usuarios lean el XML de los archivos de modelo, considere la posibilidad de usar monikers de clave calificados. 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 vuelva a cargar correctamente. Por lo tanto, si define una clase de dominio a la que se hace referencia mediante monikers de clave calificados, debe considerar las 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 el Explorador DSL, expanda XML Serialization Behavior\Class Data\<la clase de dominio>\Element Data.

    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 de esa clase.

  2. Establezca como identificador de serialización = true para la clase de dominio.

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

Para establecer una clase de dominio que sea referenciada por identificadores de clave calificados

  • Establezca como la clave de moniker 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 Name. El nombre del elemento de es y la clave de moniker de es, estas propiedades del dominio se inicializan a 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 nombres clave cualificados, es posible que dos elementos del modelo de un usuario tengan el mismo valor en la propiedad de clave. Por ejemplo, si el DSL tiene una clase Person que tiene una propiedad Name, el usuario podría establecer los nombres de dos elementos para que sean los mismos. 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 domain 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 para el DSL. En el Explorador dsl, seleccione Editor\Validation y establezca las propiedades Uses... 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 de validación Load. 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 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" />

A continuación, una de las canciones de ese álbum podría ser:

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

Sin embargo, si se hace referencia a los álbumes por ID en su lugar, los nombres 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 tendrá el prefijo del 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 hará 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 Título de la clase Álbum, el nombre o identificador del modelo no se usará en los monikers de Álbum 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, despliegue el nodo Comportamiento de Serialización XML en el Explorador de DSL. En una clase de dominio, expanda el nodo Datos de elementos 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 de 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 relación. Esta opción se establece automáticamente al agregar 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 en Datos del elemento y use los comandos de menú Mover hacia arriba o Bajar.

Personalización principal mediante código de programa

Puede reemplazar partes o todos los algoritmos de serialización.

Se recomienda estudiar el código 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 ni la deserialización de tipos de datos personalizados mediante BinaryFormatter, debido a los riesgos de seguridad asociados con BinaryFormatter.

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

Aunque no se recomienda usar BinaryFormatter por motivos de seguridad, si debe mantener la compatibilidad con modelos que usaban serialización BinaryFormatter, 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. Bajo cada uno de esos nodos hay una lista de propiedades y relaciones originadas en ese elemento. Las relaciones se representan tanto por sí mismas como dentro de 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 dsl y establezca las opciones en la ventana Propiedades.

Datos de clase Xml

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

Propiedad Descripción
Tiene un esquema de elemento personalizado Si es True, indica que la clase de dominio tiene un esquema de elemento personalizado.
Es personalizado 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 detectar instrucciones detalladas.
Clase de dominio Clase de dominio a la que se aplica este nodo de datos de clase. Sólo 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 clase de dominio.
Nombre del atributo Moniker Nombre del atributo usado en elementos de moniker para contener la referencia. Si está en blanco, se usa el nombre de la propiedad clave o del id.

En este ejemplo, es "name": <personMoniker name="/Mike Nash"/>
Nombre del elemento Moniker Nombre del elemento xml usado para monikers que hacen referencia a elementos de esta clase.

El valor predeterminado es una versión minúscula del nombre de clase con el sufijo "Moniker". Por ejemplo, personMoniker.
Moniker Type Name Nombre del tipo XSD generado para los monikers en 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 de tipo Nombre del tipo xml generado en xsd a partir 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 se aplican los datos de configuración de serialización xml. Sólo 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 los monikers. Si es false y SerializeId no es true para esta clase de dominio, los monikers se califican mediante el moniker del elemento principal del árbol de inserción.
Representación Si el valor se establece en Atributo, 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 Omitir, no se serializa.
Xml Name Nombre usado para el atributo xml o elemento 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 de rol XML

Los nodos de datos asociados al rol se encuentran debajo de los nodos de clase de origen.

Propiedad Descripción
Tiene Moniker personalizado 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 con la que se aplican estas opciones. Sólo lectura.
Omitir elemento Si es true, el nodo XML que corresponde 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 derivado del rol de origen. El valor predeterminado es el nombre de la propiedad de rol.
Usar formulario completo Si es true, cada elemento de destino o moniker 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.