Настройка хранилища файлов и сериализации XML
Когда пользователь сохраняет экземпляр или модель определенного домена языка (DSL) в Visual Studio, xml-файл создается или обновляется. Файл можно перезагрузить для повторного создания модели в Магазине.
Вы можете настроить схему сериализации, изменив параметры в разделе "Поведение сериализации XML" в обозревателе DSL. Узел в разделе "Поведение сериализации XML" для каждого класса домена, свойства и связи. Связи находятся под их исходными классами. Существуют также узлы, соответствующие классам фигуры, соединителя и схемы.
Вы также можете написать программный код для более расширенной настройки.
Примечание.
Если вы хотите сохранить модель в определенном формате, но не нужно перезагрузить ее из этой формы, рассмотрите возможность использования текстовых шаблонов для создания выходных данных из модели вместо пользовательской схемы сериализации. Дополнительные сведения см. в разделе "Создание кода на языке для конкретного домена".
Файлы модели и схемы
Каждая модель сохраняется в двух файлах:
Файл модели имеет такое имя, как
Model1.mydsl
. Он сохраняет элементы модели и связи и их свойства. Расширение файла, например.mydsl
, определяется свойством FileExtension узла Editor в определении DSL.Файл схемы имеет такое имя, как
Model1.mydsl.diagram
. Он хранит фигуры, соединители и их позиции, цвета, толщину линии и другие сведения о внешнем виде схемы. Если пользователь удаляет.diagram
файл, основные сведения в модели не теряются. Только макет схемы теряется. При открытии файла модели создается набор фигур и соединителей по умолчанию.
Изменение расширения файла DSL
Откройте определение DSL. В обозревателе DSL щелкните узел редактора.
В окно свойств измените свойство FileExtension. Не включайте инициал
.
расширения имени файла.В Обозреватель решений измените имя двух файлов шаблона элемента в DslPackage\ProjectItemTemplates. Эти файлы имеют имена, которые соответствуют этому формату:
myDsl.diagram
myDsl.myDsl
Схема сериализации по умолчанию
Чтобы создать пример для этого раздела, использовалось следующее определение 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-файлы модели были удобочитаемыми, рассмотрите возможность использования квалифицированных моникеров ключей. Однако пользователь может задать несколько элементов с одним и тем же ключом моникера. Повторяющиеся ключи могут привести к неправильной загрузке файла. Таким образом, если вы определяете класс домена, на который ссылается квалифицированный моникеры ключей, следует рассмотреть способы предотвращения сохранения пользователем файла с повторяющимися моникерами.
Установка класса домена, на который ссылается моникеры идентификаторов
Убедитесь, что Is Moniker Key предназначен
false
для каждого свойства домена в классе и его базовых классах.В обозревателе DSL разверните раздел "Поведение xml сериализации\Класс данных\<класс> домена\Элемент Data".
Убедитесь, что ключ Moniker предназначен
false
для каждого свойства домена.Если класс домена имеет базовый класс, повторите процедуру в этом классе.
Задайте идентификатор =
true
сериализации для класса домена.Это свойство можно найти в разделе "Поведение сериализации XML".
Указание класса домена, на который ссылаются квалифицированные моникеры ключей
Set Is Moniker Key для свойства домена существующего класса домена. Тип свойства должен быть
string
.В обозревателе DSL разверните раздел "Поведение xml сериализации\Класс данных\<класс> домена\Данные элемента", а затем выберите свойство домена.
В окно свойств задайте для
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.
Настройка сериализации определенного класса
Set Is Custom in the node for the class in the class under Xml Serialization Behavior.
Преобразуйте все шаблоны, создайте решение и изучите полученные ошибки компиляции. Примечания рядом с каждой ошибкой объясняют, какой код необходимо предоставить.
Предоставление собственной сериализации для всей модели
- Переопределение методов в 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, если у связи есть собственные свойства домена. |