다음을 통해 공유


파일 스토리지 및 XML Serialization 사용자 지정

사용자가 Visual Studio에서 DSL(도메인 특정 언어)의 인스턴스 또는 모델을 저장하면 XML 파일이 만들어지거나 업데이트됩니다. 이 파일을 다시 로드하면 저장소에서 모델을 다시 만들 수 있습니다.

DSL 탐색기의 Xml 직렬화 동작에서 설정을 조정하여 직렬화 체계를 사용자 지정할 수 있습니다. 모든 도메인 클래스, 속성 및 관계에 대한 Xml Serialization 동작 아래에 노드가 있습니다. 관계는 해당 원본 클래스 아래에 있습니다. 도형, 연결선, 다이어그램 클래스에 해당하는 노드도 있습니다.

고급 사용자 지정을 위해 프로그램 코드를 작성할 수도 있습니다.

참고 항목

모델을 특정 형식으로 저장하되 해당 양식에서 다시 로드할 필요가 없는 경우 사용자 지정 직렬화 체계 대신 텍스트 템플릿을 사용하여 모델에서 출력을 생성하는 것이 좋습니다. 자세한 내용은 도메인 특정 언어에서 코드 생성을 참조하세요.

모델 및 다이어그램 파일

각 모델은 다음 두 개의 파일에 저장됩니다.

  • 모델 파일에는 .와 같은 Model1.mydsl이름이 있습니다. 이 파일은 모델 요소 및 관계와 해당 속성을 저장합니다. 파일 .mydsl 확장명은 DSL 정의에서 편집기 노드의 FileExtension 속성에 의해 결정됩니다.

  • 다이어그램 파일에는 다음과 같은 Model1.mydsl.diagram이름이 있습니다. 이 파일은 도형 및 연결선과 해당 위치, 색, 선 두께 및 다이어그램 모양의 기타 세부 정보를 저장합니다. 사용자가 파일을 삭제 .diagram 하면 모델의 필수 정보가 손실되지 않습니다. 다이어그램의 레이아웃만 손실됩니다. 모델 파일을 열면 기본 셰이프 및 연결선 집합이 만들어집니다.

DSL의 파일 확장명을 변경하려면

  1. DSL 정의를 엽니다. DSL 탐색기에서 편집기 노드를 클릭합니다.

  2. 속성 창에서 FileExtension 속성을 편집합니다. 파일 이름 확장명 초기 . 를 포함하지 마세요.

  3. 솔루션 탐색기에서 DslPackage\ProjectItemTemplates의 2개 항목 템플릿 파일 이름을 변경합니다. 이러한 파일에는 다음 양식을 따르는 이름이 있습니다.

    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 노드의 이름은 도메인 클래스 이름과 동일합니다. 예를 들어 familyTreeModelperson를 지정합니다.

  • Name 및 BirthYear와 같은 도메인 속성은 XML 노드에서 특성으로 직렬화됩니다. 이 경우에도 속성 이름의 첫 글자는 소문자로 변환됩니다.

  • 각 관계는 관계의 원본 끝 내에 중첩된 XML 노드로 직렬화됩니다. 이 노드는 원본 역할 속성과 이름이 같지만 첫 글자가 소문자입니다.

    예를 들어 DSL 정의에서 이름이 People인 역할의 원본은 FamilyTree 클래스에 있습니다. XML에서 People 역할은 노드 내부에 familyTreeModel 중첩된 노드 people 로 표시됩니다.

  • 각 포함 관계의 대상 끝은 관계 아래에 중첩된 노드로 직렬화됩니다. 예를 들어 people 노드에는 여러 person 노드가 포함됩니다.

  • 각 참조 관계의 대상 끝은 대상 요소에 대한 참조를 인코딩하는 모니커로 직렬화됩니다.

    예를 들어 person 노드 아래에 children 관계가 있을 수 있습니다. 이 노드에는 다음과 같은 모니커가 포함되어 있습니다.

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

모니커 이해

모니커는 모델의 여러 부분과 다이어그램 파일 간의 상호 참조를 나타내는 데 사용됩니다. 또한 파일에서 모델 파일의 .diagram 노드를 참조하는 데 사용됩니다. 다음 두 가지 모니커 양식이 있습니다.

  • ID 모니커는 대상 요소의 GUID를 따옴표로 지정합니다. 예시:

    <personShapeMoniker Id="f79734c0-3da1-4d72-9514-848fa9e75157" />
    
  • 정규화된 키 모니커는 모니커 키라는 지정된 도메인 속성의 값으로 대상 요소를 식별합니다. 대상 요소의 모니커에는 관계 포함 트리에 부모 요소의 모니커가 접두사로 지정됩니다.

    다음 예제는 Song이라는 도메인 클래스에 포함 관계가 있는 Album이라는 도메인 클래스가 있는 DSL에서 가져옵니다.

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

    정규화된 키 모니커는 대상 클래스에 Xml Serialization 동작에서 모니커 키 옵션이 설정된 true 도메인 속성이 있는 경우에 사용됩니다. 이 예에서 이 옵션은 도메인 클래스 "Album" 및 "Song"에서 "Title"이라는 도메인 속성에 대해 설정됩니다.

정규화된 키 모니커는 ID 모니커보다 읽기 쉽습니다. 모델 파일의 XML을 사람이 읽을 수 있게 하려면 정규화된 키 모니커를 사용하는 것이 좋습니다. 그러나 사용자가 두 개 이상의 요소를 설정하여 동일한 모니커 키를 가질 수 있습니다. 중복 키로 인해 파일이 제대로 다시 로드되지 않을 수 있습니다. 따라서 정규화된 키 모니커를 사용하여 참조되는 도메인 클래스를 정의하는 경우 중복 모니커가 있는 파일을 사용자가 저장하지 못하도록 하는 방법을 고려해야 합니다.

ID 모니커에서 참조할 도메인 클래스를 설정하려면

  1. 클래스 및 해당 기본 클래스의 모든 도메인 속성에서 Is Moniker Keyfalse로 설정되어 있어야 합니다.

    1. DSL 탐색기에서 Xml Serialization Behavior\Class Data\<도메인 클래스>\Element Data를 확장합니다.

    2. 모든 도메인 속성에서 Is Moniker Keyfalse인지 확인합니다.

    3. 도메인 클래스에 기본 클래스가 있는 경우 기본 클래스에서도 이 절차를 반복합니다.

  2. 도메인 클래스의 Serialize Id = true를 설정합니다.

    이 속성은 Xml Serialization 동작에서 찾을 수 있습니다.

정규화된 키 모니커가 참조할 도메인 클래스를 설정하려면

  • 기본 도메인 클래스의 도메인 속성에서 Is Moniker Key를 설정합니다. 속성의 형식은 string이어야 합니다.

    1. DSL 탐색기에서 Xml Serialization Behavior\Class Data\<도메인 클래스>\Element Data를 확장한 다음 도메인 속성을 선택합니다.

    2. 속성 창에서 Is Moniker Keytrue로 설정합니다.

  • - 또는 -

    명명된 도메인 클래스 도구를 사용하여 새 도메인 클래스를 만듭니다.

    이 도구는 Name이라는 도메인 속성이 있는 새 클래스를 만듭니다. 이 도메인 속성의 Is Element NameIs Moniker Key 속성은 true로 초기화됩니다.

  • - 또는 -

    도메인 클래스부터 모니커 키 속성이 있는 다른 클래스까지 상속 관계를 만듭니다.

중복 모니커 방지

정규화된 키 모니커를 사용하는 경우 사용자 모델의 두 요소가 키 속성에 동일한 값을 가질 수 있습니다. 예를 들어 DSL에 Name 속성이 있는 Person 클래스가 있는 경우 사용자는 두 요소의 Name을 동일하게 설정할 수 있습니다. 모델을 파일에 저장할 수 있지만 올바르게 다시 로드되지는 않습니다.

이 상황을 방지하는 데 도움이 되는 몇 가지 방법이 있습니다.

  • 키 도메인 속성에서 Is Element Name = true를 설정합니다. DSL 정의 다이어그램에서 도메인 속성을 선택한 다음 속성 창에서 값을 설정합니다.

    사용자가 클래스의 새 인스턴스를 만들면 이 값으로 인해 도메인 속성에 다른 값이 자동으로 할당됩니다. 기본 동작은 클래스 이름의 끝에 숫자를 추가합니다. 이렇게 하면 사용자가 이름을 중복으로 변경할 수 없지만 모델을 저장하기 전에 사용자가 값을 설정하지 않은 경우에 도움이 됩니다.

  • DSL에 유효성 검사를 사용하도록 설정합니다. DSL 탐색기에서 Editor\Validation을 선택하고 Uses... 속성을 true로 설정합니다.

    모호성을 확인하는 자동으로 생성된 유효성 검사 메서드가 있습니다. 이 메서드는 Load 유효성 검사 범주에 있습니다. 이렇게 하면 사용자에게 파일을 다시 열 수 없다는 경고가 표시됩니다.

    자세한 내용은 도메인 특정 언어의 유효성 검사를 참조하세요.

모니커 경로 및 한정자

정규화된 키 모니커는 모니커 키로 끝나며, 포함 트리의 부모의 모니커가 접두사로 추가됩니다. 예를 들어 Album의 모니커가 다음과 같은 경우

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

해당 Album의 Song 중 하나는 다음이 될 수 있습니다.

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

하지만 Album이 대신 ID로 참조되는 경우 모니커는 다음과 같습니다.

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

GUID는 고유하기 때문에 부모의 모니커에 접두사를 지정하지 않습니다.

특정 도메인 속성의 값이 모델 내에서 항상 고유하다는 것을 알고 있는 경우 해당 속성에서 Is Moniker Qualifiertrue로 설정할 수 있습니다. 이렇게 하면 부모의 모니커를 사용하지 않고 한정자로 사용됩니다. 예를 들어 앨범 클래스의 타이틀 도메인 속성에 대해 Is Moniker QualifierIs Moniker Key를 둘 다 설정하는 경우 모델의 이름 또는 식별자는 앨범 및 포함된 자식의 모니커에서 사용되지 않습니다.

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

XML 구조 사용자 지정

다음 사용자 지정을 수행하려면 DSL 탐색기에서 Xml 직렬화 동작 노드를 확장합니다. 도메인 클래스에서 요소 데이터 노드를 확장하여 이 클래스에 원본이 있는 속성 및 관계의 목록을 표시합니다. 관계를 선택하고 속성 창의 옵션을 조정합니다.

  • 원본 역할 노드를 생략하고 대상 요소 목록만 남겨 두려면 Omit Element을 true로 설정합니다. 원본 클래스와 대상 클래스 간에 둘 이상의 관계가 있는 경우 이 옵션을 설정해서는 안 됩니다.

    <familyTreeModel ...>
      <!-- The following node is omitted by using Omit Element: -->
      <!-- <people> -->
        <person name="Henry VIII" .../>
        <person name="Elizabeth I" .../>
      <!-- </people> -->
    </familyTreeModel>
    
  • 관계 인스턴스를 나타내는 노드에 대상 노드를 포함하려면 Use Full Form을 설정합니다. 이 옵션은 도메인 관계에 도메인 속성을 추가하면 자동으로 설정됩니다.

    <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>
    
  • 도메인 속성을 특성 값이 아닌 요소로 저장하려면 Representation = Element를 설정합니다.

    <person name="Elizabeth I" birthYear="1533">
      <deathYear>1603</deathYear>
    </person>
    
  • 특성 및 관계가 직렬화되는 순서를 변경하려면 요소 데이터 아래의 항목을 마우스 오른쪽 단추로 클릭하고 위로 이동 또는 아래로 이동 메뉴 명령을 사용합니다.

프로그램 코드를 사용하여 주요 사용자 지정

직렬화 알고리즘의 일부 또는 전체를 바꿀 수 있습니다.

Dsl\Generated Code\Serializer.csSerializationHelper.cs의 코드를 검토하는 것이 좋습니다.

특정 클래스의 직렬화를 사용자 지정하려면

  1. Xml 직렬화 동작 아래 해당 클래스의 노드에서 Is Custom을 설정합니다.

  2. 모든 템플릿을 변환하고, 솔루션을 빌드하고, 결과 컴파일 오류를 조사합니다. 각 오류 근처의 주석에는 제공해야 하는 코드가 설명되어 있습니다.

전체 모델의 자체 직렬화를 제공하려면

  1. Dsl\GeneratedCode\SerializationHelper.cs의 메서드를 재정의합니다.

참고 항목

Visual Studio 2022 17.13부터 기본 serialization 구현은 BinaryFormatter의 보안 위험으로 인해 BinaryFormatter를 사용하여 사용자 지정 데이터 형식의 직렬화 또는 역직렬화를 더 이상 지원하지 않습니다.

도메인 속성에 사용자 지정 데이터 형식을 사용하는 경우 클래스의 serialization 메서드 SerializationHelper 를 재정의하거나 각 사용자 지정 데이터 형식을 문자열로 변환할 수 있는 기능을 구현 TypeConverter 해야 합니다.

보안상의 이유로 사용하지 BinaryFormatter 않는 것이 좋지만 serialization을 사용한 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 Serialization 동작 노드에는 각 도메인 클래스, 관계, 셰이프, 커넥터 및 다이어그램 클래스에 대한 자식 노드가 포함됩니다. 각 노드 아래에는 해당 요소에 원본이 있는 속성과 관계의 목록이 있습니다. 관계는 자체 클래스와 원본 클래스 모두에 표시됩니다.

다음 표에는 DSL 정의의 이 섹션에서 설정할 수 있는 옵션이 요약되어 있습니다. 각 경우에 DSL 탐색기에서 요소를 선택하고 속성 창에서 옵션을 설정합니다.

Xml 클래스 데이터

이러한 요소는 DSL 탐색기의 Xml Serialization Behavior\Class Data에서 찾을 수 있습니다.

속성 설명
Has Custom Element Schema True이면 도메인 클래스에 사용자 지정 요소 스키마가 있음을 나타냅니다.
Is Custom 이 도메인 클래스에 대한 고유한 serialization 및 역직렬화 코드를 작성하려면 값을 True 로 설정합니다.

솔루션을 빌드하고 오류를 조사하여 자세한 지침을 검색합니다.
도메인 클래스 이 클래스 데이터 노드가 적용되는 도메인 클래스입니다. 읽기 전용.
요소 이름 이 클래스의 요소의 Xml 노드 이름입니다. 기본값은 도메인 클래스 이름의 소문자 버전입니다.
Moniker Attribute Name 참조를 포함하기 위해 모니커 요소에 사용되는 특성의 이름입니다. 비어 있는 경우 키 속성의 이름 또는 id가 사용됩니다.

이 예제에서는 "name"입니다. <personMoniker name="/Mike Nash"/>
Moniker Element Name 이 클래스의 요소를 참조하는 모니커에 사용되는 xml 요소의 이름입니다.

기본값은 "Moniker" 접미사가 붙은 클래스 이름의 소문자 버전입니다. 예들 들어 personMoniker입니다.
Moniker Type Name 이 클래스의 요소의 모니커에 대해 생성된 xsd 형식의 이름입니다. XSD는 Dsl\Generated Code\*Schema.xsd에 있습니다.
Serialize Id True이면 요소 GUID가 파일에 포함됩니다. Is Moniker Key로 표시된 속성이 없고 DSL이 이 클래스에 대한 참조 관계를 정의하는 경우 값을 True로 설정해야 합니다.
형식 이름 지정된 도메인 클래스의 xsd에서 생성된 xml 형식의 이름입니다.
주의 이 요소와 관련된 비공식적 참고 사항입니다.

Xml 속성 데이터

Xml 속성 노드는 클래스 노드 아래에 있습니다.

속성 설명
Domain Property xml 직렬화 구성 데이터가 적용되는 속성입니다. 읽기 전용.
Is Moniker Key 값이 True설정되면 이 도메인 클래스의 인스턴스를 참조하는 모니커를 만들기 위한 키로 속성이 사용됩니다.
Is Moniker Qualifier 값이 True설정된 경우 속성은 모니커에서 한정자를 만드는 데 사용됩니다. false이고 SerializeId가 이 도메인 클래스에 대해 true가 아닌 경우 모니커는 포함 트리에 있는 부모 요소의 모니커에 의해 정규화됩니다.
표현 값이 Attribute설정된 경우 속성은 xml 특성으로 직렬화됩니다. 값이 Element로 설정되면 요소로 serialize되고 값이 Ignore설정되면 직렬화되지 않습니다.
Xml Name 속성을 나타내는 xml 특성 또는 요소에 사용되는 이름입니다. 기본적으로 이 값은 도메인 속성 이름의 소문자 버전입니다.
주의 이 요소와 관련된 비공식적 참고 사항입니다.

Xml 역할 데이터

역할 데이터 노드는 원본 클래스 노드 아래에 있습니다.

속성 설명
Has Custom Moniker 이 관계를 트래버스하는 모니커를 생성 및 확인하기 위해 자체 코드를 제공하려면 이 속성을 true로 설정합니다.

자세한 지침을 보려면 솔루션을 빌드한 다음 오류 메시지를 두 번 클릭합니다.
도메인 관계 이러한 옵션이 적용되는 관계를 지정합니다. 읽기 전용.
Omit Element true이면 원본 역할에 해당하는 XML 노드가 스키마에서 생략됩니다.

원본 클래스와 대상 클래스 간에 둘 이상의 관계가 있는 경우 이 역할 노드는 두 관계에 속하는 링크를 구분합니다. 따라서 이 경우 이 옵션을 설정하지 않는 것이 좋습니다.
Role Element Name 원본 역할에서 파생되는 XML 요소의 이름을 지정합니다. 기본값은 역할 속성 이름입니다.
Use Full Form true이면 각 대상 요소 또는 모니커가 관계를 나타내는 XML 노드로 묶입니다. 관계에 자체 도메인 속성이 있는 경우 이 속성을 true로 설정해야 합니다.