Compartilhar via


Serialização e desserialização

O WCF (Windows Communication Foundation) inclui um novo mecanismo de serialização, o DataContractSerializer. O DataContractSerializer traduz entre objetos .NET Framework e XML, em ambas as direções. Este tópico explica como o serializador funciona.

Ao serializar objetos do .NET Framework, o serializador entende uma variedade de modelos de programação de serialização, incluindo o novo modelo de contrato de dados . Para obter uma lista completa de tipos com suporte, consulte Tipos compatíveis com o Serializador de Contrato de Dados. Para obter uma introdução aos contratos de dados, consulte Como usar contratos de dados.

Ao desserializar o XML, o serializador usa as XmlReader e XmlWriter classes. Ele também dá suporte ao XmlDictionaryReader e XmlDictionaryWriter às classes para permitir que ele produza XML otimizado em alguns casos, como ao usar o formato XML binário do WCF.

O WCF também inclui um serializador complementar, o NetDataContractSerializer. NetDataContractSerializer:

  • Não é seguro. Para saber mais, confira o Guia de segurança do BinaryFormatter.
  • É semelhante aos serializadores BinaryFormatter e SoapFormatter porque também emite tipos de nomes do .NET Framework como parte dos dados serializados.
  • Ele é usado quando os mesmos tipos são compartilhados nas terminações de serialização e desserialização.

Ambos DataContractSerializer e NetDataContractSerializer derivam de uma classe base comum. XmlObjectSerializer

Aviso

O DataContractSerializer serializa cadeias de caracteres que contêm caracteres de controle com um valor hexadecimal abaixo de 20 como entidades XML. Isso pode causar um problema com um cliente não WCF ao enviar esses dados para um serviço WCF.

Criando uma instância do DataContractSerializer

Construir uma instância do DataContractSerializer é uma etapa importante. Após a construção, você não pode alterar nenhuma das configurações.

Especificando o tipo da raiz

O tipo raiz é o tipo de quais instâncias são serializadas ou desserializadas. O DataContractSerializer possui muitas sobrecargas de construtor, mas, no mínimo, um tipo raiz precisa ser fornecido usando o parâmetro type.

Um serializador criado para um determinado tipo raiz não pode ser usado para serializar (ou desserializar) outro tipo, a menos que o tipo seja derivado do tipo raiz. O exemplo a seguir mostra duas classes.

[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

Esse código cria uma instância de DataContractSerializer que pode ser usada apenas para serializar ou desserializar instâncias da classe 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.

Especificando tipos conhecidos

Se o polimorfismo estiver envolvido nos tipos que estão sendo serializados que ainda não são tratados usando o KnownTypeAttribute atributo ou algum outro mecanismo, uma lista de possíveis tipos conhecidos deve ser passada para o construtor do serializador usando o knownTypes parâmetro. Para obter mais informações sobre tipos conhecidos, consulte Tipos Conhecidos do Contrato de Dados.

O exemplo a seguir mostra uma classe, LibraryPatronque inclui uma coleção de um tipo específico, o LibraryItem. A segunda classe define o LibraryItem tipo. A terceira e quarta classes (Book e Newspaper) herdam da classe 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

O código a seguir constrói uma instância do serializador usando o knownTypes parâmetro.

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

Especificando o nome raiz padrão e o namespace

Normalmente, quando um objeto é serializado, o nome padrão e o namespace do elemento XML mais externo são determinados de acordo com o nome e o namespace do contrato de dados. Os nomes de todos os elementos internos são determinados a partir de nomes de membros de dados e seu namespace é o namespace do contrato de dados. O exemplo a seguir define os valores Name e Namespace nos construtores das classes DataContractAttribute e DataMemberAttribute.

[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

Serializar uma instância da Person classe produz XML semelhante ao seguinte.

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

No entanto, você pode personalizar o nome padrão e o namespace do elemento raiz passando os valores dos parâmetros rootName e rootNamespace para o construtor DataContractSerializer. Observe que o rootNamespace namespace não afeta os elementos contidos que correspondem aos membros de dados. Afeta apenas o namespace do elemento mais externo.

Esses valores podem ser passados como strings ou instâncias da classe XmlDictionaryString para permitir a sua otimização usando o formato XML binário.

Definindo a cota máxima de objetos

Algumas sobrecargas do construtor DataContractSerializer têm um parâmetro maxItemsInObjectGraph. Esse parâmetro determina o número máximo de objetos que o serializador serializa ou desserializa em uma única ReadObject chamada de método. (O método sempre lê um objeto raiz, mas esse objeto pode ter outros objetos em seus membros de dados. Esses objetos podem ter outros objetos e assim por diante.) O padrão é 65536. Observe que, ao serializar ou desserializar matrizes, cada entrada de matriz conta como um objeto separado. Além disso, observe que alguns objetos podem ter uma representação de memória grande e, portanto, essa cota por si só pode não ser suficiente para evitar um ataque de negação de serviço. Para obter mais informações, consulte Considerações de segurança para dados. Se você precisar aumentar essa cota além do valor padrão, é importante fazer isso nos lados de envio (serialização) e recebimento (desserialização), pois ela se aplica a ambos ao ler e gravar dados.

Viagens de ida e volta

Uma viagem de ida e volta ocorre quando um objeto é desserializado e serializado novamente em uma operação. Assim, ele vai de XML para uma instância de objeto e volta novamente para um fluxo XML.

Algumas sobrecargas de construtor do DataContractSerializer têm um parâmetro ignoreExtensionDataObject, que é definido como false por padrão. Nesse modo padrão, os dados podem ser enviados em uma viagem de ida e volta de uma versão mais recente de um contrato de dados por meio de uma versão mais antiga e voltar para a versão mais recente sem perda, desde que o contrato de dados implemente a IExtensibleDataObject interface. Por exemplo, suponha que a versão 1 do Person contrato de dados contenha os membros de dados Name e PhoneNumber, e que a versão 2 adicione um membro Nickname. Se IExtensibleDataObject for implementado, ao enviar informações da versão 2 para a versão 1, os Nickname dados serão armazenados e, em seguida, remetidos quando os dados forem serializados novamente; portanto, nenhum dado será perdido na viagem de ida e volta. Para obter mais informações, confira Contratos de dados compatíveis com encaminhamento e Controle de versão dos contratos de dados.

Preocupações de segurança e validade do esquema com viagens de ida e volta

Viagens de ida e volta podem ter implicações de segurança. Por exemplo, desserializar e armazenar grandes quantidades de dados desnecessários pode ser um risco à segurança. Pode haver preocupações de segurança sobre a retransmissão destes dados que não há como verificar, especialmente se assinaturas digitais estejam envolvidas. Por exemplo, no cenário anterior, o ponto de extremidade da versão 1 pode ser assinar um valor de Nickname que contém dados mal-intencionados. Por fim, pode haver preocupações quanto à validade do esquema: um ponto de extremidade pode querer sempre emitir dados que aderem estritamente ao seu contrato declarado e não emitir quaisquer valores adicionais. No exemplo anterior, o contrato do ponto de extremidade da versão 1 diz que ele emite apenas Name e PhoneNumber, se a validação do esquema estiver sendo usada, emitir o valor extra Nickname fará com que a validação falhe.

Habilitando e desabilitando viagens de ida e volta

Para desativar as viagens de ida e volta, não implemente a interface IExtensibleDataObject. Se você não tiver controle sobre os tipos, defina o ignoreExtensionDataObject parâmetro para true obter o mesmo efeito.

Preservação do gráfico do objeto

Normalmente, o serializador não se importa com a identidade do objeto, como no código a seguir.

[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

O código a seguir cria uma ordem de compra.

// 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

Observe que billTo e shipTo os campos são definidos como a mesma instância de objeto. No entanto, o XML gerado duplica as informações duplicadas e é semelhante ao XML a seguir.

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

No entanto, essa abordagem tem as seguintes características, que podem ser indesejáveis:

  • Desempenho. A replicação de dados é ineficiente.

  • Referências circulares. Se os objetos se referirem a si mesmos, mesmo por meio de outros objetos, serializar por replicação resultará em um loop infinito. (O serializador gera um SerializationException se isso acontece.)

  • Semântica. Às vezes, é importante preservar o fato de que duas referências são para o mesmo objeto e não para dois objetos idênticos.

Por esses motivos, algumas DataContractSerializer sobrecargas de construtor têm o preserveObjectReferences parâmetro (o padrão é false). Quando esse parâmetro é definido como true, um método especial de referências de objeto de codificação, que só o WCF entende, é usado. Quando definido como true, o exemplo de código XML agora se assemelha ao seguinte.

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

O namespace "ser" refere-se ao namespace de serialização padrão. http://schemas.microsoft.com/2003/10/Serialization/ Cada parte dos dados é serializada apenas uma vez e recebe um número de ID e os usos subsequentes resultam em uma referência aos dados já serializados.

Importante

Se os atributos "id" e "ref" estiverem presentes no contrato XMLElementde dados, o atributo "ref" será respeitado e o atributo "id" será ignorado.

É importante entender as limitações desse modo:

  • O XML que o DataContractSerializer gera com preserveObjectReferences configurado para true não é interoperável com outras tecnologias, podendo ser acessado apenas por outra instância de DataContractSerializer, também com preserveObjectReferences configurado para true.

  • Não há suporte para metadados (esquema) para esse recurso. O esquema produzido é válido apenas para o caso quando preserveObjectReferences é definido como false.

  • Esse recurso pode fazer com que o processo de serialização e desserialização seja executado mais lentamente. Embora os dados não precisem ser replicados, comparações de objetos extras devem ser executadas nesse modo.

Cuidado

Quando o preserveObjectReferences modo está habilitado, é especialmente importante definir o maxItemsInObjectGraph valor como a cota correta. Devido à maneira como as matrizes são tratadas nesse modo, é fácil para um invasor construir uma pequena mensagem mal-intencionada que resulta em um grande consumo de memória limitado apenas pela maxItemsInObjectGraph cota.

Especificando um substituto de contrato de dados

Algumas sobrecargas de construtor do DataContractSerializer têm um parâmetro dataContractSurrogate, que pode ser definido como null por padrão. Caso contrário, você poderá usá-lo para especificar um substituto de contrato de dados, que é um tipo que implementa a IDataContractSurrogate interface. Em seguida, você pode usar a interface para personalizar o processo de serialização e desserialização. Para obter mais informações, consulte Substitutos do Contrato de Dados.

Serialização

As informações a seguir se aplicam a qualquer classe que herda do XmlObjectSerializer, incluindo as classes DataContractSerializer e NetDataContractSerializer.

Serialização simples

A maneira mais básica de serializar um objeto é passá-lo para o WriteObject método. Há três sobrecargas, cada uma para escrever em um Stream, XmlWriter ou XmlDictionaryWriter. Com a sobrecarga Stream, a saída é XML na codificação UTF-8. Com a sobrecarga XmlDictionaryWriter, o serializador otimiza a saída para XML binário.

Ao usar o WriteObject método, o serializador usa o nome e o namespace padrão para o elemento wrapper e o grava junto com o conteúdo (consulte a seção anterior "Especificando o nome raiz padrão e o namespace").

O exemplo a seguir demonstra a escrita com um 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)

Isso produz XML semelhante ao seguinte.

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

Serialização passo a passo

Use os WriteStartObjectmétodos , WriteObjectContente WriteEndObject para gravar o elemento final, escreva o conteúdo do objeto e feche o elemento wrapper, respectivamente.

Observação

Não há nenhuma sobrecarga de Stream desses métodos.

Essa serialização passo a passo tem dois usos comuns. Uma delas é inserir conteúdos como atributos ou comentários entre WriteStartObject e WriteObjectContent, conforme mostrado no exemplo a seguir.

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)

Isso produz XML semelhante ao seguinte.

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

Outro uso comum é evitar o uso de WriteStartObject e WriteEndObject em sua totalidade e escrever seu próprio elemento wrapper personalizado (ou até mesmo deixar de escrever um wrapper), conforme mostrado no código a seguir.

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

Isso produz XML semelhante ao seguinte.

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

Observação

Usar a serialização etapa por etapa pode resultar em XML não conforme ao esquema.

Desserialização

As informações a seguir se aplicam a qualquer classe que herda do XmlObjectSerializer, incluindo as classes DataContractSerializer e NetDataContractSerializer.

A maneira mais básica de desserializar um objeto é chamar uma das sobrecargas de método ReadObject. Há três sobrecargas, cada uma para ler comum XmlDictionaryReader, XmlReader ou Stream. Note que a sobrecarga Stream cria uma representação textual XmlDictionaryReader que não está protegida por nenhuma cota e deve ser utilizada apenas para ler dados confiáveis.

Observe também que o objeto retornado pelo ReadObject método deve ser convertido no tipo apropriado.

O código a seguir constrói uma instância de DataContractSerializer e de XmlDictionaryReader, e depois desserializa uma instância de 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)

Antes de chamar o método ReadObject, posicione a leitora XML no elemento wrapper ou em um nó de não conteúdo que precede o elemento wrapper. Você pode fazer isso chamando o método Read de XmlReader ou sua derivação e testando o NodeType, conforme mostrado no código a seguir.

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

Observe que você pode ler atributos neste elemento wrapper antes de enviar o leitor para ReadObject.

Ao usar uma das sobrecargas simples ReadObject , o desserializador procura o nome e o namespace padrão no elemento wrapper (consulte a seção anterior, "Especificando o nome raiz padrão e o namespace") e gera uma exceção se encontrar um elemento desconhecido. No exemplo anterior, o <Person> elemento wrapper é esperado. O IsStartObject método é chamado para verificar se o leitor está posicionado em um elemento nomeado conforme o esperado.

Há uma maneira de desabilitar essa verificação de nome do elemento wrapper; algumas sobrecargas do ReadObject método aceitam o parâmetro Booleano verifyObjectName, que é definido como true por padrão. Quando definido como false, o nome e o namespace do elemento wrapper são ignorados. Isso é útil para ler XML que foi escrito usando o mecanismo de serialização passo a passo descrito anteriormente.

Usando o NetDataContractSerializer

A principal diferença entre o DataContractSerializer e o NetDataContractSerializer é que o DataContractSerializer usa nomes de contrato de dados, enquanto o NetDataContractSerializer produz nomes completos de assembly e de tipo do .NET Framework no XML serializado. Isso significa que exatamente os mesmos tipos devem ser compartilhados entre os pontos de extremidade de serialização e desserialização. Isso significa que o mecanismo de tipos conhecidos não é necessário com NetDataContractSerializer, porque os tipos exatos a serem desserializados são sempre conhecidos.

No entanto, vários problemas podem ocorrer:

  • Segurança. Qualquer tipo encontrado no XML que está sendo desserializado é carregado. Isso pode ser explorado para forçar o carregamento de tipos mal-intencionados. Usar o NetDataContractSerializer com dados não confiáveis deve ser feito somente se um Associador de Serialização for utilizado (usando a propriedade Binder ou o parâmetro de construtor). O associador permite que apenas tipos seguros sejam carregados. O mecanismo Associador é idêntico ao usado pelos tipos no System.Runtime.Serialization.

  • Controle de versão.. O uso de nomes completos de tipos e assemblies no XML restringe severamente a maneira como os tipos podem ser versionados. O exemplo a seguir não pode ser modificado: nomes de tipo, namespaces, nomes de assembly e versões de assembly. Definir a propriedade AssemblyFormat ou o parâmetro do construtor como Simple em vez do valor padrão de Full permite alterações de versão do assembly, mas não para tipos de parâmetros genéricos.

  • Interoperabilidade. Como os nomes de tipo e assembly do .NET Framework estão incluídos no XML, plataformas diferentes do .NET Framework não podem acessar os dados resultantes.

  • Desempenho. Gravar os nomes de tipo e assembly aumenta significativamente o tamanho do XML resultante.

Esse mecanismo é semelhante à serialização binária ou SOAP usada pela comunicação remota do .NET Framework (especificamente, o BinaryFormatter e o SoapFormatter).

Usar o NetDataContractSerializer é semelhante ao uso do DataContractSerializer, com as seguintes diferenças:

  • Os construtores não exigem que você especifique um tipo de raiz. Você pode serializar qualquer tipo usando a mesma instância do NetDataContractSerializer.

  • Os construtores não aceitam uma lista de tipos conhecidos. O mecanismo de tipos conhecidos será desnecessário se os nomes de tipo forem serializados no XML.

  • Os construtores não aceitam um substituto do contrato de dados. Em vez disso, eles aceitam um ISurrogateSelector parâmetro chamado surrogateSelector (que é mapeado para a propriedade SurrogateSelector). Este é um mecanismo substituto herdado.

  • Os construtores aceitam um parâmetro chamado assemblyFormat do FormatterAssemblyStyle que mapeia para a propriedade AssemblyFormat. Conforme discutido anteriormente, isso pode ser usado para aprimorar os recursos de controle de versão do serializador. Isso é idêntico ao FormatterAssemblyStyle mecanismo na serialização binária ou SOAP.

  • Os construtores aceitam um StreamingContext parâmetro chamado context que corresponde à propriedade Context. Você pode usar isso para passar informações para os tipos que estão sendo serializados. Esse uso é idêntico ao do StreamingContext mecanismo usado em outras System.Runtime.Serialization classes.

  • Os métodos Serialize e Deserialize são sinônimos para os métodos WriteObject e ReadObject. Elas existem para fornecer um modelo de programação mais consistente com serialização binária ou SOAP.

Para obter mais informações sobre esses recursos, consulte Serialização Binária.

Os formatos XML que NetDataContractSerializer e DataContractSerializer utilizam normalmente não são compatíveis. Ou seja, tentar serializar com um desses serializadores e desserializar com o outro não é um cenário suportado.

Além disso, observe que o NetDataContractSerializer não gera o nome completo do tipo e do assembly do .NET Framework para cada nó no grafo de objetos. Ele gera essas informações apenas onde elas são ambíguas. Isto é, ele gera no nível do objeto raiz e para qualquer caso polimórfico.

Consulte também