Поделиться через


Настройка хранилища файлов и сериализации XML

Когда пользователь сохраняет экземпляр или модель определенного домена языка (DSL) в Visual Studio, xml-файл создается или обновляется. Файл можно перезагрузить для повторного создания модели в Магазине.

Вы можете настроить схему сериализации, изменив параметры в разделе "Поведение сериализации XML" в обозревателе DSL. Узел в разделе "Поведение сериализации XML" для каждого класса домена, свойства и связи. Связи находятся под их исходными классами. Существуют также узлы, соответствующие классам фигуры, соединителя и схемы.

Вы также можете написать программный код для более расширенной настройки.

Примечание.

Если вы хотите сохранить модель в определенном формате, но не нужно перезагрузить ее из этой формы, рассмотрите возможность использования текстовых шаблонов для создания выходных данных из модели вместо пользовательской схемы сериализации. Дополнительные сведения см. в разделе "Создание кода на языке для конкретного домена".

Файлы модели и схемы

Каждая модель сохраняется в двух файлах:

  • Файл модели имеет такое имя, как Model1.mydsl. Он сохраняет элементы модели и связи и их свойства. Расширение файла, например.mydsl, определяется свойством FileExtension узла Editor в определении DSL.

  • Файл схемы имеет такое имя, как Model1.mydsl.diagram. Он хранит фигуры, соединители и их позиции, цвета, толщину линии и другие сведения о внешнем виде схемы. Если пользователь удаляет .diagram файл, основные сведения в модели не теряются. Только макет схемы теряется. При открытии файла модели создается набор фигур и соединителей по умолчанию.

Изменение расширения файла DSL

  1. Откройте определение DSL. В обозревателе DSL щелкните узел редактора.

  2. В окно свойств измените свойство FileExtension. Не включайте инициал . расширения имени файла.

  3. В Обозреватель решений измените имя двух файлов шаблона элемента в DslPackage\ProjectItemTemplates. Эти файлы имеют имена, которые соответствуют этому формату:

    myDsl.diagram

    myDsl.myDsl

Схема сериализации по умолчанию

Чтобы создать пример для этого раздела, использовалось следующее определение DSL.

Схема определения DSL — модель семейства

Этот DSL использовался для создания модели, которая имеет следующий внешний вид на экране.

Обозреватель, панель элементов и схема семейного дерева

Эта модель была сохранена, а затем снова открыта в текстовом редакторе 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>

Обратите внимание на следующие моменты о сериализованной модели:

  • Каждый XML-узел имеет имя, которое совпадает с именем класса домена, за исключением того, что начальная буква является строчным регистром. Например, familyTreeModel и person.

  • Свойства домена, такие как Name и BirthYear, сериализуются в виде атрибутов в XML-узлах. Опять же, начальный символ имени свойства преобразуется в нижний регистр.

  • Каждая связь сериализуется как XML-узел, вложенный в исходную часть связи. Узел имеет то же имя, что и свойство исходной роли, но с начальным символом нижнего регистра.

    Например, в определении DSL роль, которая называется People , создается в классе FamilyTree . В XML роль "Люди " представлена с именем people узла, вложенного в familyTreeModel узел.

  • Целевой конец каждой связи внедрения сериализуется как узел, вложенный в связь. Например, people узел содержит несколько person узлов.

  • Целевой конец каждой ссылочной связи сериализуется как моникер, который кодирует ссылку на целевой элемент.

    Например, под person узлом может быть children связь. Этот узел содержит моникеры, такие как:

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

Общие сведения о Моникерах

Моникеры используются для представления перекрестных ссылок между различными частями файлов модели и схемы. Они также используются в .diagram файле для ссылки на узлы в файле модели. Существует две формы моникера:

  • Идентификатор моникеров цитирует GUID целевого элемента. Например:

    <personShapeMoniker Id="f79734c0-3da1-4d72-9514-848fa9e75157" />
    
  • Квалифицированные моникеры ключей определяют целевой элемент по значению указанного свойства домена, называемого моникером. Моникер целевого элемента префиксируется моникером родительского элемента в дереве связей внедрения.

    Следующие примеры взяты из DSL, в котором есть класс домена с именем Альбом, который имеет отношение внедрения к классу домена с именем Song:

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

    Квалифицированные моникеры ключей используются, если целевой класс имеет свойство домена, для которого для параметра Is Moniker Key задано значение true в поведении сериализации XML. В примере этот параметр задается для свойств домена с именем Title в классах домена "Альбом" и "Песня".

Квалифицированные моникеры ключей проще читать, чем моникеры идентификаторов. Если вы планируете, чтобы XML-файлы модели были удобочитаемыми, рассмотрите возможность использования квалифицированных моникеров ключей. Однако пользователь может задать несколько элементов с одним и тем же ключом моникера. Повторяющиеся ключи могут привести к неправильной загрузке файла. Таким образом, если вы определяете класс домена, на который ссылается квалифицированный моникеры ключей, следует рассмотреть способы предотвращения сохранения пользователем файла с повторяющимися моникерами.

Установка класса домена, на который ссылается моникеры идентификаторов

  1. Убедитесь, что Is Moniker Key предназначен false для каждого свойства домена в классе и его базовых классах.

    1. В обозревателе DSL разверните раздел "Поведение xml сериализации\Класс данных\<класс> домена\Элемент Data".

    2. Убедитесь, что ключ Moniker предназначен false для каждого свойства домена.

    3. Если класс домена имеет базовый класс, повторите процедуру в этом классе.

  2. Задайте идентификатор = true сериализации для класса домена.

    Это свойство можно найти в разделе "Поведение сериализации XML".

Указание класса домена, на который ссылаются квалифицированные моникеры ключей

  • Set Is Moniker Key для свойства домена существующего класса домена. Тип свойства должен быть string.

    1. В обозревателе DSL разверните раздел "Поведение xml сериализации\Класс данных\<класс> домена\Данные элемента", а затем выберите свойство домена.

    2. В окно свойств задайте для trueзначения "Moniker Key".

  • - или -

    Создайте новый класс домена с помощью средства именованного класса домена.

    Это средство создает новый класс, имеющий свойство домена с именем Name. Свойства ключа Is Element Name и Is Moniker Key свойства этого свойства домена инициализируются trueв .

  • - или -

    Создайте связь наследования из класса домена к другому классу, который имеет свойство ключа моникера.

Избегайте дубликатов Моникеров

Если вы используете квалифицированные моникеры ключей, возможно, что два элемента в модели пользователя могут иметь одно и то же значение в свойстве ключа. Например, если в dsL есть класс Person, имеющий имя свойства, пользователь может задать имена двух элементов таким же образом. Хотя модель может быть сохранена в файле, она не будет правильно загружена.

Существует несколько методов, которые помогут избежать этой ситуации:

  • Задайте имя = true элемента для свойства ключевого домена. Выберите свойство домена на схеме определения DSL и задайте значение в окно свойств.

    Когда пользователь создает новый экземпляр класса, это значение приводит к автоматическому присвоению свойства домена другого значения. Поведение по умолчанию добавляет число в конец имени класса. Это не предотвращает изменение имени пользователя на дубликат, но помогает в случае, если пользователь не задает значение перед сохранением модели.

  • Включите проверку для DSL. В обозревателе DSL выберите "Редактор\Проверка" и задайте для свойств Use... значение true.

    Существует автоматически созданный метод проверки, который проверяет неоднозначность. Метод находится в Load категории проверки. Это гарантирует, что пользователь будет предупреждать о том, что может быть невозможно повторно открыть файл.

    Дополнительные сведения см. в разделе "Проверка" на языке конкретного домена.

Моникер Путь и квалификаторы

Квалифицированный моникер ключей заканчивается моникером и префиксируется моникером своего родительского элемента в дереве внедрения. Например, если моникер альбома:

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

Затем одна из песен в этом альбоме может быть:

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

Тем не менее, если альбомы ссылаются на идентификатор вместо этого, то моникеры будут следующим образом:

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

Обратите внимание, что поскольку GUID является уникальным, он никогда не префиксируется моникером родительского элемента.

Если вы знаете, что определенное свойство домена всегда будет иметь уникальное значение в модели, для этого свойства можно задать значение Is Moniker Qualifiertrue. Это приводит к использованию его в качестве квалификатора без использования моникера родительского элемента. Например, если вы задаете как Moniker Qualifier, так и Is Moniker Key для свойства домена Title класса Album, имя или идентификатор модели не используется в моникерах для альбома и его внедренных дочерних элементов:

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

Настройка структуры XML

Чтобы сделать следующие настройки, разверните узел поведения сериализации XML в обозревателе DSL. В классе домена разверните узел данных элемента, чтобы просмотреть список свойств и связей, исходных в этом классе. Выберите связь и настройте его параметры в окно свойств.

  • Задайте для элемента Omit значение true, чтобы опустить узел исходной роли, оставив только список целевых элементов. Этот параметр не следует задавать, если между исходными и целевыми классами существует несколько связей.

    <familyTreeModel ...>
      <!-- The following node is omitted by using Omit Element: -->
      <!-- <people> -->
        <person name="Henry VIII" .../>
        <person name="Elizabeth I" .../>
      <!-- </people> -->
    </familyTreeModel>
    
  • Задайте для внедрения целевых узлов в узлы, представляющие экземпляры связей, с помощью полной формы . Этот параметр устанавливается автоматически при добавлении свойств домена в отношение домена.

    <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>
    
  • Задайте для элемента представления = свойство домена, сохраненное в качестве элемента, а не в качестве значения атрибута.

    <person name="Elizabeth I" birthYear="1533">
      <deathYear>1603</deathYear>
    </person>
    
  • Чтобы изменить порядок сериализации атрибутов и связей, щелкните правой кнопкой мыши элемент в разделе "Данные элементов" и используйте команды меню "Переместить вверх " или "Переместить вниз ".

Основная настройка с помощью кода программы

Можно заменить части или все алгоритмы сериализации.

Мы рекомендуем изучить код в Dsl\Generated Code\Serializer.cs и SerializationHelper.cs.

Настройка сериализации определенного класса

  1. Set Is Custom in the node for the class in the class under Xml Serialization Behavior.

  2. Преобразуйте все шаблоны, создайте решение и изучите полученные ошибки компиляции. Примечания рядом с каждой ошибкой объясняют, какой код необходимо предоставить.

Предоставление собственной сериализации для всей модели

  1. Переопределение методов в Dsl\GeneratedCode\SerializationHelper.cs

Примечание.

Начиная с Visual Studio 2022 17.13 реализация сериализации по умолчанию больше не поддерживает сериализацию или десериализацию пользовательских типов данных с помощью BinaryFormatter из-за рисков безопасности с Помощью BinaryFormatter.

Если вы используете пользовательский тип данных для любых свойств домена, необходимо переопределить методы сериализации в SerializationHelper классе или реализовать TypeConverter возможность преобразования каждого пользовательского типа данных в строку и из нее.

Хотя мы не рекомендуем использовать BinaryFormatter по соображениям безопасности, если необходимо поддерживать обратную совместимость со старыми моделями, которые использовали BinaryFormatter сериализацию, можно реализовать TypeConverter десериализацию двоичных данных. Следующий фрагмент кода служит шаблоном для реализации этой совместимости:

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

Параметры в поведении сериализации XML

В обозревателе DSL узел поведения сериализации XML содержит дочерний узел для каждого класса домена, связи, фигуры, соединителя и класса схемы. В каждом из этих узлов находится список свойств и связей, исходных в этом элементе. Отношения представлены как в собственном праве, так и в их исходных классах.

В следующей таблице перечислены параметры, которые можно задать в этом разделе определения DSL. В каждом случае выберите элемент в обозревателе DSL и задайте параметры в окно свойств.

Данные класса XML

Эти элементы находятся в обозревателе DSL в разделе "Поведение xml-сериализации\Данные класса".

Свойство Description
Имеет настраиваемую схему элементов Значение True указывает, что класс домена имеет настраиваемую схему элементов.
Настраивается Задайте значение True , если вы хотите написать собственный код сериализации и десериализации для этого класса домена.

Создайте решение и изучите ошибки, чтобы найти подробные инструкции.
Доменный класс Класс домена, к которому применяется этот узел данных класса. Только чтение.
Имя элемента Имя узла XML для элементов этого класса. Значение по умолчанию — это версия нижнего регистра имени класса домена.
Имя атрибута Moniker Имя атрибута, используемого в моникер-элементах для хранения ссылки. Если пусто, используется имя свойства ключа или идентификатора.

В этом примере это "name": <personMoniker name="/Mike Nash"/>
Имя элемента Moniker Имя xml-элемента, используемого для моникеров, ссылающихся на элементы этого класса.

Значение по умолчанию — это строчная версия имени класса суффиксом "Moniker". Например, personMoniker.
Имя типа Moniker Имя типа xsd, созданного для моникеров в элементы этого класса. XSD находится в dsl\Generated Code\*Schema.xsd
Идентификатор сериализации Если значение True, идентификатор GUID элемента включен в файл. Значение должно быть задано в значение True , если нет свойства, помеченного как Is Moniker Key , и DSL определяет ссылочные связи с этим классом.
Тип Имя Имя xml-типа, созданного в xsd из указанного класса домена.
Примечания. Неофициальные заметки, связанные с этим элементом

Данные свойства XML

Узлы свойств XML находятся под узлами класса.

Свойство Description
Свойство домена Свойство, к которому применяются данные конфигурации сериализации XML. Только чтение.
Ключ Моникера Если для значения задано значение True, свойство используется в качестве ключа для создания моникеров, ссылающихся на экземпляры этого класса домена.
Моникер квалификатор Если для значения задано значение True, свойство используется для создания квалификатора в моникерах. Если значение false, и если SerializeId не соответствует этому классу домена, моникеры квалифицированы моникером родительского элемента в дереве внедрения.
Представление Если для значения задано значение Attribute, свойство сериализуется как xml-атрибут; если для значения задано значение Element, сериализуется как элемент; если значение имеет значение Ignore, то оно не сериализуется.
Xml-имя Имя, используемое для xml-атрибута или элемента, представляющего свойство. По умолчанию значение является нижней версией имени свойства домена.
Примечания. Неофициальные заметки, связанные с этим элементом

Данные xml-роли

Узлы данных роли находятся в узлах исходного класса.

Свойство Description
Имеет пользовательский моникер Задайте для этого значение true, если вы хотите указать собственный код для создания и разрешения моникеров, которые проходят через эту связь.

Подробные инструкции по созданию решения и дважды щелкните сообщения об ошибках.
Доменная связь Указывает связь, к которой применяются эти параметры. Только чтение.
Элемент Omit Если значение true, xml-узел, соответствующий исходной роли, не указан в схеме.

Если между исходными и целевыми классами существует несколько связей, этот узел роли различает связи, принадлежащие двум отношениям. Поэтому мы рекомендуем не задать этот параметр в этом случае.
Имя элемента Role Указывает имя XML-элемента, производного от исходной роли. Значением по умолчанию является имя свойства роли.
Использование полной формы Если значение true, каждый целевой элемент или моникер заключен в XML-узел, представляющий связь. Это значение должно иметь значение true, если у связи есть собственные свойства домена.