다음을 통해 공유


직렬화 및 역직렬화

Windows Communication Foundation(WCF)에는 새로운 직렬화 엔진인 DataContractSerializer이 포함되어 있습니다. . DataContractSerializer NET Framework 개체와 XML을 양방향으로 변환합니다. 이 항목에서는 serializer의 작동 방식을 설명합니다.

.NET Framework 개체를 직렬화할 때 serializer는 새 데이터 계약 모델을 포함하여 다양한 serialization 프로그래밍 모델을 이해합니다. 지원되는 형식의 전체 목록은 데이터 계약 직렬 변환기에서 지원하는 형식을 참조하세요. 데이터 계약에 대한 소개는 데이터 계약 사용을 참조하세요.

XML을 역직렬화할 때 Serializer는 XmlReaderXmlWriter 클래스를 사용합니다. 또한 WCF 이진 XML 형식을 사용하는 경우와 같이 일부 상황에서 최적화된 XML을 생성할 수 있도록 "XmlDictionaryReader" 및 "XmlDictionaryWriter" 클래스도 지원합니다.

WCF에는 보조 직렬화 도구인 NetDataContractSerializer. NetDataContractSerializer :

  • 안전하지 않습니다 . 자세한 내용은 BinaryFormatter 보안 가이드를 참조하세요.
  • BinaryFormatter 직렬 변환기와 SoapFormatter 직렬 변환기와 비슷하며, 직렬화된 데이터의 일부로 .NET Framework 형식 이름을 내보냅니다.
  • 직렬화에서 동일한 형식이 공유되고 역직렬화가 끝날 때 사용됩니다.

둘 다 DataContractSerializer 공통 NetDataContractSerializer 기본 클래스 XmlObjectSerializer에서 파생됩니다.

경고

DataContractSerializer 16진수 값이 20 미만인 컨트롤 문자가 포함된 문자열을 XML 엔터티로 serialize합니다. 이로 인해 이러한 데이터를 WCF 서비스로 보낼 때 WCF가 아닌 클라이언트에 문제가 발생할 수 있습니다.

DataContractSerializer 인스턴스 만들기

인스턴스 DataContractSerializer 를 생성하는 것은 중요한 단계입니다. 생성 후에는 설정을 변경할 수 없습니다.

루트 형식 지정

루트 형식은 인스턴스가 직렬화되거나 역직렬화되는 형식입니다. DataContractSerializer에는 많은 생성자 오버로드가 있지만, 최소한 type 매개 변수를 사용하여 루트 형식을 제공해야 합니다.

특정 루트 형식에 대해 만든 serializer는 루트 형식에서 파생되지 않는 한 다른 형식을 직렬화(또는 역직렬화)하는 데 사용할 수 없습니다. 다음 예제에서는 두 클래스를 보여 줍니다.

[DataContract]
public class Person
{
    // Code not shown.
}

[DataContract]
public class PurchaseOrder
{
    // Code not shown.
}
<DataContract()> _
Public Class Person
    ' Code not shown.
End Class

<DataContract()> _
Public Class PurchaseOrder
    ' Code not shown.
End Class

이 코드는 DataContractSerializer 클래스의 인스턴스를 직렬화하거나 역직렬화하는 데만 사용할 수 있는 Person의 인스턴스를 생성합니다.

DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
// This can now be used to serialize/deserialize Person but not PurchaseOrder.
Dim dcs As New DataContractSerializer(GetType(Person))
' This can now be used to serialize/deserialize Person but not PurchaseOrder.

알려진 형식 지정

직렬화되는 형식에 다형성이 관련되어 있으며, KnownTypeAttribute 속성 또는 다른 메커니즘으로 아직 처리되지 않은 경우, 가능한 알려진 형식의 목록을 knownTypes 매개변수를 사용하여 serializer의 생성자에 전달해야 합니다. 알려진 형식에 대한 자세한 내용은 데이터 계약 알려진 형식을 참조하세요.

다음 예제에서는 특정 형식LibraryPatron의 컬렉션을 포함하는 클래스LibraryItem를 보여줍니다. 두 번째 클래스는 형식을 LibraryItem 정의합니다. 세 번째와 네 번째 클래스(BookNewspaper)는 LibraryItem 클래스에서 상속됩니다.

[DataContract]
public class LibraryPatron
{
    [DataMember]
    public LibraryItem[] borrowedItems;
}
[DataContract]
public class LibraryItem
{
    // Code not shown.
}

[DataContract]
public class Book : LibraryItem
{
    // Code not shown.
}

[DataContract]
public class Newspaper : LibraryItem
{
    // Code not shown.
}
<DataContract()> _
Public Class LibraryPatron
    <DataMember()> _
    Public borrowedItems() As LibraryItem
End Class

<DataContract()> _
Public Class LibraryItem
    ' Code not shown.
End Class

<DataContract()> _
Public Class Book
    Inherits LibraryItem
    ' Code not shown.
End Class

<DataContract()> _
Public Class Newspaper
    Inherits LibraryItem
    ' Code not shown.
End Class

다음 코드는 매개 변수를 사용하여 serializer의 인스턴스를 생성합니다 knownTypes .

// Create a serializer for the inherited types using the knownType parameter.
Type[] knownTypes = new Type[] { typeof(Book), typeof(Newspaper) };
DataContractSerializer dcs =
new DataContractSerializer(typeof(LibraryPatron), knownTypes);
// All types are known after construction.
' Create a serializer for the inherited types using the knownType parameter.
Dim knownTypes() As Type = {GetType(Book), GetType(Newspaper)}
Dim dcs As New DataContractSerializer(GetType(LibraryPatron), knownTypes)
' All types are known after construction.

기본 루트 이름 및 네임스페이스 지정

일반적으로 개체가 직렬화되면 가장 바깥쪽 XML 요소의 기본 이름 및 네임스페이스는 데이터 계약 이름 및 네임스페이스에 따라 결정됩니다. 모든 내부 요소의 이름은 데이터 멤버 이름에서 결정되며 해당 네임스페이스는 데이터 계약의 네임스페이스입니다. 다음 예제는 NameNamespace 클래스의 생성자에서 DataContractAttributeDataMemberAttribute 값을 설정합니다.

[DataContract(Name = "PersonContract", Namespace = "http://schemas.contoso.com")]
public class Person2
{
    [DataMember(Name = "AddressMember")]
    public Address theAddress;
}

[DataContract(Name = "AddressContract", Namespace = "http://schemas.contoso.com")]
public class Address
{
    [DataMember(Name = "StreetMember")]
    public string street;
}
<DataContract(Name:="PersonContract", [Namespace]:="http://schemas.contoso.com")> _
Public Class Person2
    <DataMember(Name:="AddressMember")> _
    Public theAddress As Address
End Class

<DataContract(Name:="AddressContract", [Namespace]:="http://schemas.contoso.com")> _
Public Class Address
    <DataMember(Name:="StreetMember")> _
    Public street As String
End Class

클래스의 인스턴스를 직렬화하면 Person 다음과 유사한 XML이 생성됩니다.

<PersonContract xmlns="http://schemas.contoso.com">  
  <AddressMember>  
    <StreetMember>123 Main Street</StreetMember>  
   </AddressMember>  
</PersonContract>  

그러나 생성자에 rootNamerootNamespace 매개 변수의 값을 전달하여 루트 요소의 기본 이름과 네임스페이스를 사용자 지정할 수 있습니다. rootNamespace는 데이터 멤버에 해당하는 포함된 요소의 네임스페이스에 영향을 주지 않는다는 점을 유의하세요. 가장 바깥쪽 요소의 네임스페이스에만 영향을 줍니다.

이러한 값은 이진 XML 형식을 사용하여 최적화할 수 있도록 클래스의 XmlDictionaryString 문자열 또는 인스턴스로 전달될 수 있습니다.

최대 개체 할당량 설정

일부 DataContractSerializer 생성자 오버로드에는 매개 변수가 있습니다 maxItemsInObjectGraph . 이 매개 변수는 serializer가 단일 ReadObject 메서드 호출에서 직렬화하거나 역직렬화하는 최대 개체 수를 결정합니다. (메서드는 항상 하나의 루트 개체를 읽지만 이 개체의 데이터 멤버에 다른 개체가 있을 수 있습니다. 이러한 개체에는 다른 개체가 있을 수 있습니다.) 기본값은 65536입니다. 배열을 직렬화하거나 역직렬화할 때 모든 배열 항목은 별도의 개체로 계산됩니다. 또한 일부 개체에는 큰 메모리 표현이 있을 수 있으므로 이 할당량만으로는 서비스 거부 공격을 방지하기에 충분하지 않을 수 있습니다. 자세한 내용은 데이터에 대한 보안 고려 사항을 참조하세요. 이 할당량을 기본값 이상으로 늘려야 하는 경우 데이터를 읽고 쓸 때 둘 다에 적용되므로 전송(직렬화) 및 수신(역직렬화) 쪽 모두에서 이 작업을 수행하는 것이 중요합니다.

왕복 여행

한 작업에서 개체가 역직렬화되고 다시 직렬화될 때 왕복 이 발생합니다. 따라서 XML에서 개체 인스턴스로 이동하고 다시 XML 스트림으로 이동합니다.

일부 DataContractSerializer 생성자 오버로드에는 기본적으로 ignoreExtensionDataObject로 설정된 false 매개 변수가 있습니다. 이 기본 모드에서는 데이터 계약이 IExtensibleDataObject 인터페이스를 구현하는 한, 데이터가 이전 버전을 통해 최신 버전으로 왕복 전송하여도 손실 없이 최신 버전으로 돌아올 수 있습니다. 예를 들어 Person 데이터 계약의 버전 1은 NamePhoneNumber 데이터 멤버를 포함하며, 버전 2는 Nickname 멤버를 추가한다. 구현된 경우 IExtensibleDataObject 버전 2에서 버전 1 Nickname 로 정보를 보낼 때 데이터가 저장되고 데이터가 다시 직렬화될 때 다시 내보내므로 왕복에서 데이터가 손실되지 않습니다. 자세한 내용은 Forward-Compatible 데이터 계약데이터 계약 버전 관리를 참조하세요.

왕복과 관련된 보안 및 스키마 유효성 문제

왕복은 보안에 영향을 미칠 수 있습니다. 예를 들어 많은 양의 불필요한 데이터를 역직렬화하고 저장하는 것은 보안 위험일 수 있습니다. 특히 디지털 서명이 관련된 경우 확인할 방법이 없다는 것을 이 데이터를 다시 내보내는 것에 대한 보안 문제가 있을 수 있습니다. 예를 들어 이전 시나리오에서 버전 1 엔드포인트는 악성 데이터가 포함된 값에 Nickname 서명할 수 있습니다. 마지막으로 스키마 유효성 문제가 있을 수 있습니다. 엔드포인트는 항상 추가 값이 아닌 명시된 계약을 엄격하게 준수하는 데이터를 내보내려고 할 수 있습니다. 이전 예제에서 버전 1 엔드포인트의 계약에는 NamePhoneNumber만 내보낸다고 되어 있으며, 스키마 유효성 검사가 사용될 때 추가 Nickname 값을 내보내면 유효성 검사가 실패하게 됩니다.

왕복 기능 활성화 및 비활성화

왕복 기능을 끄려면 인터페이스 IExtensibleDataObject를 구현하지 마세요. 형식을 제어할 수 없는 경우 매개 변수를 ignoreExtensionDataObject 설정하여 true 동일한 효과를 얻을 수 있습니다.

개체 그래프 보존

일반적으로 serializer는 다음 코드와 같이 개체 ID를 신경 쓰지 않습니다.

[DataContract]
public class PurchaseOrder
{
    [DataMember]
    public Address billTo;
    [DataMember]
    public Address shipTo;
}

[DataContract]
public class Address
{
    [DataMember]
    public string street;
}
<DataContract()> _
Public Class PurchaseOrder

    <DataMember()> _
    Public billTo As Address

    <DataMember()> _
    Public shipTo As Address

End Class

<DataContract()> _
Public Class Address

    <DataMember()> _
    Public street As String

End Class

다음 코드는 구매 주문을 만듭니다.

// Construct a purchase order:
Address adr = new Address();
adr.street = "123 Main St.";
PurchaseOrder po = new PurchaseOrder();
po.billTo = adr;
po.shipTo = adr;
' Construct a purchase order:
Dim adr As New Address()
adr.street = "123 Main St."
Dim po As New PurchaseOrder()
po.billTo = adr
po.shipTo = adr

billToshipTo 필드가 동일한 개체 인스턴스로 설정된 것을 확인하십시오. 그러나 생성된 XML은 중복된 정보를 복제하며 다음 XML과 유사합니다.

<PurchaseOrder>  
  <billTo><street>123 Main St.</street></billTo>  
  <shipTo><street>123 Main St.</street></shipTo>  
</PurchaseOrder>  

그러나 이 방법에는 바람직하지 않을 수 있는 다음과 같은 특성이 있습니다.

  • 성능. 데이터를 복제하는 것은 비효율적입니다.

  • 순환 참조입니다. 개체가 다른 개체를 통해서도 자신을 참조하는 경우 복제를 통해 직렬화하면 무한 루프가 발생합니다. (이 경우에는 직렬 변환기가 SerializationException 오류를 발생시킵니다.)

  • 의미론. 경우에 따라 두 개의 참조가 동일한 개체에 대한 것임을 보존하고, 동일하지만 다른 두 개체에 대한 것이 아님을 명확히 하는 것이 중요합니다.

이러한 이유로 일부 DataContractSerializer 생성자 오버로드에는 preserveObjectReferences 매개 변수가 있습니다(기본값은 false). 이 매개 변수를 true설정하면 WCF만 이해하는 개체 참조를 인코딩하는 특수 메서드가 사용됩니다. 로 true설정하면 XML 코드 예제가 다음과 유사합니다.

<PurchaseOrder ser:id="1">  
  <billTo ser:id="2"><street ser:id="3">123 Main St.</street></billTo>  
  <shipTo ser:ref="2"/>  
</PurchaseOrder>  

"ser" 네임스페이스는 표준 serialization 네임스페이스를 http://schemas.microsoft.com/2003/10/Serialization/나타냅니다. 각 데이터 조각은 한 번만 직렬화되고 ID 번호가 지정되며, 이후에 사용하면 이미 직렬화된 데이터에 대한 참조가 생성됩니다.

중요합니다

데이터 계약에 XMLElement"id" 및 "ref" 특성이 모두 있는 경우 "ref" 특성이 적용되고 "id" 특성이 무시됩니다.

이 모드의 제한 사항을 이해하는 것이 중요합니다.

  • DataContractSerializer가 설정된 preserveObjectReferences으로 XML을 생성하면, 다른 기술과 상호 운용되지 않고 또한 trueDataContractSerializer로 설정된 다른 preserveObjectReferences 인스턴스에서만 액세스할 수 있습니다.

  • 이 기능에 대한 메타데이터(스키마) 지원은 없습니다. 생성된 스키마는 preserveObjectReferences이(가) false으로 설정된 경우에만 유효합니다.

  • 이 기능을 사용하면 직렬화 및 역직렬화 프로세스가 느리게 실행될 수 있습니다. 데이터를 복제할 필요는 없지만 이 모드에서는 추가 개체 비교를 수행해야 합니다.

주의

preserveObjectReferences 모드를 사용할 때, maxItemsInObjectGraph 값을 올바른 할당량으로 설정하는 것이 특히 중요합니다. 이 모드에서 배열을 처리하는 방식 때문에, 공격자는 할당량 maxItemsInObjectGraph에 의해서만 제한되는 큰 메모리 사용을 초래하는 작은 악성 메시지를 쉽게 생성할 수 있습니다.

데이터 계약 서로게이트 지정

일부 DataContractSerializer 생성자 오버로드에는 dataContractSurrogate 매개 변수가 있으며, 이 매개 변수는 null로 설정될 수 있습니다. 그렇지 않으면 데이터 계약 서로게이트, 즉 인터페이스IDataContractSurrogate를 구현하는 형식을 지정하는 데 사용할 수 있습니다. 그런 다음 인터페이스를 사용하여 serialization 및 deserialization 프로세스를 사용자 지정할 수 있습니다. 자세한 내용은 데이터 계약 서로게이트를 참조하세요.

직렬화

다음 정보는 XmlObjectSerializer 클래스로부터 상속받는 모든 클래스, 포함하여 DataContractSerializerNetDataContractSerializer 클래스에 적용됩니다.

단순 직렬화

개체를 직렬화하는 가장 기본적인 방법은 개체를 메서드에 WriteObject 전달하는 것입니다. 세 가지 오버로드가 있으며, 각각은 Stream, XmlWriter, XmlDictionaryWriter에 쓰기 위한 것이 있습니다. 오버로드를 사용하면 Stream 출력은 UTF-8 인코딩의 XML입니다. 오버로드 XmlDictionaryWriter를 사용하면 serializer가 이진 XML을 위한 출력을 최적화합니다.

이 메서드를 WriteObject 사용하는 경우 serializer는 래퍼 요소의 기본 이름 및 네임스페이스를 사용하고 내용과 함께 작성합니다(이전의 "기본 루트 이름 및 네임스페이스 지정" 섹션 참조).

다음 예제에서는 XmlDictionaryWriter를 사용하여 작성하는 방법을 보여 줍니다.

Person p = new Person();
DataContractSerializer dcs =
    new DataContractSerializer(typeof(Person));
XmlDictionaryWriter xdw =
    XmlDictionaryWriter.CreateTextWriter(someStream,Encoding.UTF8 );
dcs.WriteObject(xdw, p);
Dim p As New Person()
Dim dcs As New DataContractSerializer(GetType(Person))
Dim xdw As XmlDictionaryWriter = _
    XmlDictionaryWriter.CreateTextWriter(someStream, Encoding.UTF8)
dcs.WriteObject(xdw, p)

이렇게 하면 다음과 유사한 XML이 생성됩니다.

<Person>  
  <Name>Jay Hamlin</Name>  
  <Address>123 Main St.</Address>  
</Person>  

단계By-Step 직렬화

WriteStartObject, WriteObjectContentWriteEndObject 메서드를 사용하여 끝 요소를 작성하고, 개체 내용을 쓰고, 래퍼 요소를 각각 닫습니다.

비고

이러한 메서드의 오버로드가 없습니다 Stream .

이 단계별 직렬화에는 두 가지 일반적인 용도가 있습니다. 하나는 다음 예제와 같이 WriteStartObjectWriteObjectContent 사이에 특성 또는 주석과 같은 내용을 삽입하는 것입니다.

dcs.WriteStartObject(xdw, p);
xdw.WriteAttributeString("serializedBy", "myCode");
dcs.WriteObjectContent(xdw, p);
dcs.WriteEndObject(xdw);
dcs.WriteStartObject(xdw, p)
xdw.WriteAttributeString("serializedBy", "myCode")
dcs.WriteObjectContent(xdw, p)
dcs.WriteEndObject(xdw)

이렇게 하면 다음과 유사한 XML이 생성됩니다.

<Person serializedBy="myCode">  
  <Name>Jay Hamlin</Name>  
  <Address>123 Main St.</Address>  
</Person>  

또 다른 일반적인 용도는 WriteStartObjectWriteEndObject을 전혀 사용하지 않고 사용자 지정 래퍼 요소를 작성하거나 래퍼 작성을 완전히 생략하는 것입니다. 이는 다음 코드에 나타나 있습니다.

xdw.WriteStartElement("MyCustomWrapper");
dcs.WriteObjectContent(xdw, p);
xdw.WriteEndElement();
xdw.WriteStartElement("MyCustomWrapper")
dcs.WriteObjectContent(xdw, p)
xdw.WriteEndElement()

이렇게 하면 다음과 유사한 XML이 생성됩니다.

<MyCustomWrapper>  
  <Name>Jay Hamlin</Name>  
  <Address>123 Main St.</Address>  
</MyCustomWrapper>  

비고

단계별 serialization을 사용하면 스키마가 잘못된 XML이 발생할 수 있습니다.

역직렬화

다음 정보는 XmlObjectSerializer 클래스로부터 상속받는 모든 클래스, 포함하여 DataContractSerializerNetDataContractSerializer 클래스에 적용됩니다.

개체를 역직렬화하는 가장 기본적인 방법은 메서드 오버로드 중 하나를 호출하는 ReadObject 것입니다. 3개의 오버로드가 있으며 각각 XmlDictionaryReader, XmlReader, 또는 Stream을 사용하는 경우에 해당합니다. Stream 오버로드는 할당량으로 보호되지 않는 XmlDictionaryReader 유형의 텍스트를 생성하며, 신뢰할 수 있는 데이터를 읽는 데에만 사용해야 합니다.

또한 ReadObject 메서드가 반환하는 개체는 적절한 형식으로 변환되어야 합니다.

다음 코드는 DataContractSerializerXmlDictionaryReader 인스턴스를 생성한 다음, Person 인스턴스를 역직렬화합니다.

DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
FileStream fs = new FileStream(path, FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());

Person p = (Person)dcs.ReadObject(reader);
Dim dcs As New DataContractSerializer(GetType(Person))
Dim fs As New FileStream(path, FileMode.Open)
Dim reader As XmlDictionaryReader = _
   XmlDictionaryReader.CreateTextReader(fs, New XmlDictionaryReaderQuotas())

Dim p As Person = CType(dcs.ReadObject(reader), Person)

메서드를 ReadObject 호출하기 전에 래퍼 요소 또는 래퍼 요소 앞에 있는 비컨텐트 노드에 XML 판독기를 배치합니다. 다음 코드는 Read 또는 그 파생의 XmlReader 메서드를 호출하고 NodeType을 테스트하여 이 작업을 수행할 수 있음을 보여줍니다.

DataContractSerializer ser = new DataContractSerializer(typeof(Person),
"Customer", @"http://www.contoso.com");
FileStream fs = new FileStream(path, FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
while (reader.Read())
{
    switch (reader.NodeType)
    {
        case XmlNodeType.Element:
            if (ser.IsStartObject(reader))
            {
                Console.WriteLine("Found the element");
                Person p = (Person)ser.ReadObject(reader);
                Console.WriteLine($"{p.Name} {p.Address}    id:{2}");
            }
            Console.WriteLine(reader.Name);
            break;
    }
}
Dim ser As New DataContractSerializer(GetType(Person), "Customer", "http://www.contoso.com")
Dim fs As New FileStream(path, FileMode.Open)
Dim reader As XmlDictionaryReader = XmlDictionaryReader.CreateTextReader(fs, New XmlDictionaryReaderQuotas())

While reader.Read()
    Select Case reader.NodeType
        Case XmlNodeType.Element
            If ser.IsStartObject(reader) Then
                Console.WriteLine("Found the element")
                Dim p As Person = CType(ser.ReadObject(reader), Person)
                Console.WriteLine("{0} {1}", _
                                   p.Name, p.Address)
            End If
            Console.WriteLine(reader.Name)
    End Select
End While

ReadObject을(를) 전달하기 전에 이 래퍼 요소의 속성을 읽을 수 있습니다.

단순 ReadObject 오버로드 중 하나를 사용하는 경우 역직렬 변환기는 래퍼 요소에서 기본 이름 및 네임스페이스를 찾고(이전 섹션인 "기본 루트 이름 및 네임스페이스 지정" 참조) 알 수 없는 요소를 찾으면 예외를 throw합니다. 앞의 예제에서는 <Person> 래퍼 요소가 예상됩니다. 이 IsStartObject 메서드는 판독기가 예상된 이름으로 지정된 요소에 위치하고 있는지를 확인하기 위해 호출됩니다.

이 래퍼 요소 이름 확인을 비활성화하는 방법이 있습니다. ReadObject 메서드의 일부 오버로드는 부울 매개 변수 verifyObjectName를 취하며, 이는 기본적으로 true로 설정되어 있습니다. 로 false설정하면 래퍼 요소의 이름 및 네임스페이스가 무시됩니다. 이는 앞에서 설명한 단계별 serialization 메커니즘을 사용하여 작성된 XML을 읽는 데 유용합니다.

NetDataContractSerializer 사용

DataContractSerializer는 데이터 계약 이름을 사용하는 반면, NetDataContractSerializer는 직렬화된 XML에서 전체 .NET Framework 어셈블리 및 형식 이름을 출력하는 것이 주된 차이점입니다. 즉, 직렬화와 역직렬화 엔드포인트 간에 정확히 동일한 형식을 공유해야 합니다. 결과적으로, 역직렬화할 정확한 형식이 항상 알려지므로 NetDataContractSerializer에 알려진 형식 메커니즘이 필요하지 않습니다.

그러나 다음과 같은 몇 가지 문제가 발생할 수 있습니다.

  • 보안. 역직렬화되는 XML에 있는 모든 형식이 로드됩니다. 악의적인 유형의 로드를 강제할 수 있도록 악용될 수 있습니다. NetDataContractSerializer( 속성 또는 생성자 매개 변수 사용)이 사용되는 경우에만 Binder 신뢰할 수 없는 데이터를 사용해야 합니다. 바인더는 안전한 형식만 로드할 수 있도록 허용합니다. 바인더 메커니즘은 System.Runtime.Serialization 네임스페이스에서 사용하는 타입과 동일합니다.

  • 버전 관리. XML에서 전체 형식 및 어셈블리 이름을 사용하면 형식의 버전 관리 방법이 심각하게 제한됩니다. 형식 이름, 네임스페이스, 어셈블리 이름 및 어셈블리 버전을 변경할 수 없습니다. AssemblyFormat 속성 또는 생성자 매개 변수를 기본값 Simple 대신에 설정하면 Full 어셈블리 버전이 변경되지만 제네릭 매개 변수 형식에는 적용되지 않습니다.

  • 상호 운용성. .NET Framework 형식 및 어셈블리 이름은 XML에 포함되므로 .NET Framework 이외의 플랫폼은 결과 데이터에 액세스할 수 없습니다.

  • 성능. 형식 및 어셈블리 이름을 작성하면 결과 XML의 크기가 크게 증가합니다.

이 메커니즘은 .NET Framework 원격(특히 BinaryFormatterSoapFormatter)에서 사용하는 이진 또는 SOAP 직렬화와 유사합니다.

사용 NetDataContractSerializer 은 다음과 같은 차이점이 있는 DataContractSerializer사용과 유사합니다.

  • 생성자는 루트 형식을 지정할 필요가 없습니다. 동일한 NetDataContractSerializer 인스턴스를 사용하여 모든 유형을 직렬화할 수 있습니다.

  • 생성자는 알려진 형식 목록을 허용하지 않습니다. 형식 이름이 XML로 serialize되는 경우 알려진 형식 메커니즘은 필요하지 않습니다.

  • 생성자는 데이터 계약 서로게이트를 허용하지 않습니다. 대신, ISurrogateSelector이라는 매개 변수를 surrogateSelector으로 수락하고, 이는 SurrogateSelector 속성으로 매핑됩니다. 이는 레거시 서로게이트 메커니즘입니다.

  • 생성자는 assemblyFormat 속성에 매핑되는 FormatterAssemblyStyle 매개 변수인 AssemblyFormat를 수락합니다. 앞에서 설명한 대로 직렬 변환기의 버전 관리 기능을 향상시키는 데 사용할 수 있습니다. 이진 또는 SOAP 직렬화의 FormatterAssemblyStyle 메커니즘과 동일합니다.

  • 생성자는 StreamingContext 속성에 매핑되는 context 매개변수인 Context를 허용합니다. 이를 사용하여 정보를 serialize되는 형식으로 전달할 수 있습니다. 이 사용법은 다른 StreamingContext 클래스에서 System.Runtime.Serialization 사용되는 메커니즘과 동일합니다.

  • SerializeDeserialize 메서드는 WriteObjectReadObject 메서드의 별칭입니다. 이러한 요소들은 이진 또는 SOAP 직렬화를 통해 보다 일관된 프로그래밍 모델을 제공하기 위해 설계되었습니다.

이러한 기능에 대한 자세한 내용은 바이너리 직렬화를 참조하세요.

NetDataContractSerializerDataContractSerializer이 사용하는 XML 형식은 일반적으로 호환되지 않습니다. 즉, 이러한 직렬화 도구 중 하나로 직렬화한 후, 다른 도구로 역직렬화를 시도하는 것은 지원되지 않는 시나리오입니다.

또한 개체 그래프의 NetDataContractSerializer 각 노드에 대한 전체 .NET Framework 형식 및 어셈블리 이름은 출력되지 않습니다. 모호한 경우에만 해당 정보를 출력합니다. 즉, 루트 객체 수준에서 그리고 모든 다형적 경우에 대해 출력됩니다.

참고하십시오