Serializzazione e deserializzazione

Windows Communication Foundation (WCF) include un nuovo motore di serializzazione, DataContractSerializer. DataContractSerializer esegue la conversione tra oggetti .NET Framework e XML in entrambe le direzioni. In questo argomento viene illustrato il funzionamento del serializzatore.

Durante la serializzazione di oggetti .NET Framework, il serializzatore è in grado di comprendere numerosi modelli di programmazione della serializzazione, incluso il nuovo modello di contratto di dati. Per un elenco completo dei tipi supportati, vedere Types Supported by the Data Contract Serializer. Per un'introduzione ai contratti dati, vedere Using Data Contracts.

Durante la deserializzazione di XML, il serializzatore utilizza le classi XmlReader e XmlWriter . Supporta inoltre le classi XmlDictionaryReader e XmlDictionaryWriter per produrre, in alcuni casi, XML ottimizzato, ad esempio quando viene usato il formato XML binario di WCF.

WCF include anche un serializzatore complementare, NetDataContractSerializer. NetDataContractSerializer:

  • Non sicuro. Per altre informazioni, vedere la guida alla sicurezza BinaryFormatter.
  • È simile ai serializzatori BinaryFormatter e SoapFormatter perché emette anche nomi di tipo .NET Framework come parte dei dati serializzati.
  • Viene usato quando gli stessi tipi sono condivisi alle estremità di serializzazione e deserializzazione.

Sia DataContractSerializer che NetDataContractSerializer derivano da una classe base comune, XmlObjectSerializer.

Avviso

DataContractSerializer serializza stringhe che contengono caratteri di controllo con un valore esadecimale inferiore a 20 come entità XML. Questa situazione potrebbe provocare un problema con un client non WCF durante l'invio di dati di questo tipo a un servizio WCF.

Creazione di un'istanza DataContractSerializer

La creazione di un'istanza di DataContractSerializer è un passaggio importante. Dopo la costruzione, non è possibile modificare nessuna di queste impostazioni.

Specifica del tipo radice

Il tipo radice è il tipo delle istanze che vengono serializzate o deserializzate. DataContractSerializer ha numerosi overload del costruttore, tuttavia è necessario fornire almeno un tipo radice utilizzando il parametro type .

Un serializzatore creato per un certo tipo radice non può essere utilizzato per serializzare (o deserializzare) un altro tipo, a meno che il tipo non sia derivato dal tipo radice. Nell'esempio che segue vengono illustrate due classi.

[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

Questo codice costruisce un'istanza di DataContractSerializer che può essere utilizzata solo per serializzare o deserializzare istanze della 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.

Specifica di tipi noti

Se i tipi serializzati implicano un polimorfismo che non è già gestito utilizzando l'attributo KnownTypeAttribute o un qualche altro meccanismo, è necessario passare al costruttore del serializzatore un elenco di possibili tipi noti utilizzando il parametro knownTypes . Per altre informazioni sui tipi noti, vedere Tipi noti del contratto di dati.

Nell'esempio di codice seguente viene illustrata una classe, LibraryPatron, che comprende una raccolta di un tipo specifico LibraryItem. La seconda classe definisce il tipo LibraryItem . La terza e la quarta classe,Book e Newspaper, ereditano dalla 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

Nel codice seguente viene creata un'istanza del serializzatore utilizzando il parametro 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.

Specifica del nome principale e dello spazio dei nomi predefiniti

In genere, quando un oggetto viene serializzato, il nome e lo spazio dei nomi predefiniti dell'elemento XML più esterno vengono determinati in base al nome del contratto dati e allo spazio dei nomi. I nomi di tutti gli elementi interni vengono determinati dai nomi dei membri dati e il loro spazio dei nomi è lo spazio dei nomi del contratto dati. Nell'esempio seguente vengono impostati i valori Name e Namespace nei costruttori delle classi 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

La serializzazione di un'istanza della classe Person produce un XML simile al seguente.

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

È tuttavia possibile personalizzare il nome e lo spazio dei nomi predefiniti dell'elemento radice passando i valori dei parametri rootName e rootNamespace al costruttore DataContractSerializer . Si noti che rootNamespace non influisce sullo spazio dei nomi degli elementi contenuti che corrispondono ai membri dati. Influisce solo sullo spazio dei nomi dell'elemento più esterno.

Questi valori possono essere passati come stringhe o come istanze della classe XmlDictionaryString per consentire la loro ottimizzazione utilizzando il formato XML binario.

Impostazione della quota massima di oggetti

Alcuni overload del costruttore DataContractSerializer hanno un parametro maxItemsInObjectGraph . Tale parametro determina il numero massimo di oggetti serializzati o deserializzati dal serializzatore in una singola chiamata al metodo ReadObject . Questo metodo legge sempre un oggetto radice che, tuttavia, potrebbe contenere altri oggetti come membri dei propri dati. Tali oggetti possono a loro volta contenere altri oggetti, e così via. Il valore predefinito è 65536. Si noti che, in caso di serializzazione o deserializzazione di matrici, ogni elemento della matrice viene considerato come un oggetto separato. Inoltre, poiché per alcuni oggetti è possibile una vasta rappresentazione in memoria, tale quota da sola potrebbe non essere sufficiente per impedire attacchi di tipo Denial of Service. Per altre informazioni, vedere Considerazioni sulla sicurezza per i dati. Se è necessario aumentare la quota oltre il valore predefinito, è importante aumentarla sia sul lato di invio (serializzazione) sia su quello di ricezione (deserializzazione) poiché si applica sia durante la lettura che durante la scrittura dei dati.

Percorsi di andata e ritorno

Si verifica un percorso di andata e ritorno quando un oggetto viene deserializzato e serializzato di nuovo in un'unica operazione. Pertanto, passa da XML a un'istanza dell'oggetto e torna indietro in un flusso XML.

Alcuni overload del costruttore DataContractSerializer hanno un parametro ignoreExtensionDataObject , la cui impostazione predefinita è false . In questa modalità predefinita, è possibile inviare i dati su un percorso di andata e ritorno da una versione più recente di un contratto dati a una versione precedente e di nuovo indietro alla versione più recente senza alcuna perdita, a condizione che il contratto dati implementi l'interfaccia IExtensibleDataObject . Si supponga, ad esempio, che la versione 1 del contratto dati Person contenga i membri dati Name e PhoneNumber e che la versione 2 aggiunga un membro Nickname . Se IExtensibleDataObject viene implementato, durante l'invio di informazioni dalla versione 2 alla versione 1 i dati Nickname vengono memorizzati ed emessi di nuovo alla successiva serializzazione; i dati non vengono persi nel percorso di andata e ritorno. Per altre informazioni, vedere Contratti dati compatibili con inoltro e Controllo delle versioni del contratto di dati.

Problemi di sicurezza e validità dello schema in caso di percorsi di andata e ritorno

I percorsi di andata e ritorno possono avere implicazioni di sicurezza. La deserializzazione e memorizzazione di grandi quantità di dati estranei, ad esempio, possono rappresentare un rischio per la sicurezza. Possono esservi problemi di sicurezza quando vengono emessi di nuovo dati che non è assolutamente possibile verificare, specie se implicano firme digitali. Nello scenario precedente, ad esempio, l'endpoint della versione 1 potrebbe firmare un valore Nickname che contiene dati dannosi. Infine, potrebbero verificarsi problemi di validità dello schema poiché un endpoint potrebbe desiderare di emettere sempre dati strettamente conformi al contratto dichiarato e nessun valore aggiuntivo. Nell'esempio precedente, il contratto dell'endpoint della versione 1 asserisce che emette solo Name e PhoneNumbere, se viene utilizzata la convalida dello schema, l'emissione del valore Nickname aggiuntivo causa l'insuccesso della convalida.

Attivazione e disattivazione di percorsi di andata e ritorno

Per disattivare i percorsi di andata e ritorno, non implementare l'interfaccia IExtensibleDataObject . Se non si ha alcun controllo sui tipi, impostare il parametro ignoreExtensionDataObject su true per ottenere lo stesso effetto.

Conservazione dell'oggetto grafico

In genere, il serializzatore non si preoccupa dell'identità dell'oggetto, come illustrato nel codice seguente.

[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

Nel codice seguente viene creato un ordine di acquisto.

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

Si noti che i campi billTo e shipTo sono impostati sulla stessa istanza dell'oggetto. L'XML generato, tuttavia, duplica le informazioni duplicate ed è simile all'XML seguente.

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

Questo approccio ha tuttavia le caratteristiche seguenti, che potrebbero essere indesiderate:

  • Prestazioni. Replicare i dati non è efficiente.

  • Riferimenti circolari. Se gli oggetti fanno riferimento a se stessi, anche tramite altri oggetti, la serializzazione tramite la replica comporta un ciclo infinito. In questo caso, il serializzatore genera una SerializationException .

  • Semantica. Talvolta è importante mantenere due riferimenti allo stesso oggetto e non a due oggetti identici.

Per queste ragioni, alcuni overload del costruttore DataContractSerializer hanno un parametro preserveObjectReferences (l'impostazione predefinita è false). Quando questo parametro è impostato su true, viene usato un metodo speciale di riferimento all'oggetto di codifica, che riconosce solo WCF. Quando è impostato su true, l'esempio di codice XML è simile al seguente.

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

Lo spazio dei nomi "ser" fa riferimento allo spazio dei nomi di serializzazione standard, http://schemas.microsoft.com/2003/10/Serialization/. Ogni blocco di dati viene serializzato solo una volta e gli viene fornito un numero ID. Gli utilizzi successivi comportano un riferimento ai dati già serializzati.

Importante

Se entrambi gli attributi "id" e "ref" sono presenti nel contratto dati XMLElement, l'attributo "ref" viene rispettato e l'attributo "id" viene ignorato.

È importante capire le limitazioni di questa modalità:

  • L'XML prodotto da DataContractSerializer con preserveObjectReferences impostato su true non è interoperativo con nessun'altra tecnologia ed è possibile accedervi solo da un'altra istanza DataContractSerializer , anche con preserveObjectReferences impostato su true.

  • Non esiste supporto di metadati (schema) per questa funzionalità. Lo schema prodotto è valido solo quando preserveObjectReferences è impostato su false.

  • Questa funzionalità può rallentare il processo di serializzazione e di deserializzazione. Anche se i dati non devono essere replicati, i confronti degli oggetti aggiuntivi devono essere eseguiti in questa modalità.

Attenzione

Quando la modalità preserveObjectReferences è attivata, è particolarmente importante impostare il valore maxItemsInObjectGraph sulla quota corretta. A causa del modo in cui le matrici sono gestite in questa modalità, è facile per l'autore di un attacco costruire un piccolo messaggio dannoso che comporta un grande consumo di memoria limitato solo dalla quota maxItemsInObjectGraph .

Specifica di un surrogato del contratto dati

Alcuni overload del costruttore DataContractSerializer hanno un parametro dataContractSurrogate che può essere impostato su null. In caso contrario, è possibile utilizzarlo per specificare un surrogato del contratto datiche è un tipo che implementa l'interfaccia IDataContractSurrogate . È quindi possibile utilizzare l'interfaccia per personalizzare il processo di serializzazione e di deserializzazione. Per altre informazioni, vedere Surrogati del contratto dati.

Serializzazione

Le informazioni seguenti si applicano a qualsiasi classe che eredita da XmlObjectSerializer, incluse le classi DataContractSerializer e NetDataContractSerializer .

Serializzazione semplice

La modalità più elementare per serializzare un oggetto consiste nel passarlo al metodo WriteObject . Esistono tre overload, per scrivere rispettivamente in un Stream, in un XmlWritero in un XmlDictionaryWriter. Con l'overload Stream , l'output è XML nella codifica UTF-8. Con l'overload XmlDictionaryWriter , il serializzatore ottimizza l'output per XML binario.

Quando si usa il metodo WriteObject, il serializzatore usa il nome e lo spazio dei nomi predefiniti per l'elemento wrapper e lo scrive insieme al contenuto (vedere la sezione precedente "Specifica del nome principale e dello spazio dei nomi predefiniti").

Nell'esempio seguente viene illustrato come scrivere con 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)

Viene prodotto un XML simile al seguente.

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

Serializzazione dettagliata

Utilizzare i metodi WriteStartObject, WriteObjectContente WriteEndObject rispettivamente per scrivere l'elemento finale, scrivere il contenuto dell'oggetto e chiudere l'elemento wrapper.

Nota

Non esistono overload Stream di questi metodi.

Questa serializzazione dettagliata ha due utilizzi comuni. Nel primo caso, viene utilizzata per inserire contenuto, ad esempio attributi o commenti tra WriteStartObject e WriteObjectContent, come illustrato nell'esempio seguente.

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)

Viene prodotto un XML simile al seguente.

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

Nel secondo caso, viene utilizzata per evitare di utilizzare WriteStartObject e WriteEndObject e scrivere l'elemento wrapper personalizzato (o per evitare di scrivere un wrapper), come illustrato nel codice seguente.

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

Viene prodotto un XML simile al seguente.

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

Nota

L'utilizzo della serializzazione dettagliata può comportare un XML di schema non valido.

Deserializzazione

Le informazioni seguenti si applicano a qualsiasi classe che eredita da XmlObjectSerializer, incluse le classi DataContractSerializer e NetDataContractSerializer .

La modalità più elementare per deserializzare un oggetto consiste nel chiamare uno degli overload del metodo ReadObject . Esistono tre overload, rispettivamente per la lettura con un XmlDictionaryReader, un XmlReadero un Stream. Si noti che l'overload Stream crea un XmlDictionaryReader testuale che non è protetto da nessuna quota e deve essere utilizzato solo per leggere dati attendibili.

Si noti inoltre che è necessario eseguire il cast dell'oggetto restituito dal metodo ReadObject sul tipo appropriato.

Nel codice seguente viene creata un'istanza di DataContractSerializer e di XmlDictionaryReader, quindi viene deserializzata un'istanza 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)

Prima di chiamare il metodo ReadObject , posizionare il lettore XML sull'elemento wrapper o su un nodo non di contenuto che precede l'elemento wrapper. A tale fine, chiamare il metodo Read di XmlReader o la sua derivazione e testare NodeType, come illustrato nel codice seguente.

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("{0} {1}    id:{2}",
                    p.Name , p.Address);
            }
            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

Si noti che è possibile leggere gli attributi in questo elemento wrapper prima di passare il lettore a ReadObject.

Quando viene usato uno degli overload ReadObject semplici, il deserializzatore cerca il nome e lo spazio dei nomi predefiniti nell'elemento wrapper (vedere la sezione precedente, "Specifica del nome principale e dello spazio dei nomi predefiniti") e, se trova un elemento sconosciuto, genera un'eccezione. Nell'esempio precedente è previsto l'elemento wrapper <Person> . Per verificare che il lettore sia posizionato su un elemento denominato come previsto, viene chiamato il metodo IsStartObject .

Il controllo del nome di un elemento wrapper può essere disattivato. Alcuni overload del metodo ReadObject prendono il parametro booleano verifyObjectName, la cui impostazione predefinita è true . Quando è impostato su false, il nome e lo spazio dei nomi dell'elemento wrapper vengono ignorati. Ciò è utile per leggere l'XML scritto utilizzando il meccanismo di serializzazione dettagliata descritto in precedenza.

Utilizzo di NetDataContractSerializer

La differenza principale tra DataContractSerializer e NetDataContractSerializer è data dal fatto che DataContractSerializer usa nomi del contratto dati, mentre NetDataContractSerializer genera nomi di assembly e dei tipi .NET Framework completi nell'XML serializzato. Ciò significa che devono essere condivisi esattamente gli stessi tipi tra gli endpoint di serializzazione e di deserializzazione. Il meccanismo dei tipi noti non è pertanto richiesto con NetDataContractSerializer perché i tipi esatti da deserializzare sono sempre conosciuti.

Possono tuttavia verificarsi numerosi problemi:

  • Sicurezza. Viene caricato qualsiasi tipo trovato nell'XML che viene deserializzato. Questo comportamento può essere sfruttato per forzare il caricamento di tipi dannosi. È consigliabile utilizzare NetDataContractSerializer con dati non attendibili solo se viene utilizzato un gestore di associazione della serializzazione (tramite la proprietà Binder o il parametro del costruttore). Il gestore di associazione consente che vengano caricati solo i tipi sicuri. Il meccanismo del gestore di associazione è identico a quello utilizzato dai tipi nello spazio dei nomi System.Runtime.Serialization .

  • Controllo delle versioni. L'utilizzo di nomi di assembly e di tipo completi nell'XML limita rigidamente il modo in cui è possibile controllare le versioni dei tipi. Non è possibile modificare gli elementi seguenti: nomi dei tipi, spazi dei nomi, nomi degli assembly e versioni degli assembly. L'impostazione della proprietà AssemblyFormat o del parametro del costruttore su Simple anziché sul valore predefinito di Full consente di modificare la versione dell'assembly, fatta eccezione per i tipi di parametro generici.

  • Interoperabilità. Dato che i nomi degli assembly e dei tipi .NET Framework sono inclusi nell'XML, piattaforme diverse da .NET Framework non possono accedere ai dati risultanti.

  • Prestazioni. La scrittura dei nomi di tipi e assembly aumenta notevolmente le dimensioni dell'XML risultante.

Questo meccanismo è simile alla serializzazione SOAP o binaria usata da .NET Framework Remoting (nello specifico, BinaryFormatter e SoapFormatter).

L'utilizzo di NetDataContractSerializer è simile a quello di DataContractSerializer, tranne che per le differenze seguenti:

  • I costruttori non richiedono che venga specificato un tipo radice. È possibile serializzare qualsiasi tipo con la stessa istanza di NetDataContractSerializer.

  • I costruttori non accettano un elenco di tipi noti. Il meccanismo dei tipi noti è non necessario se i nomi dei tipi sono serializzati nell'XML.

  • I costruttori non accettano un surrogato del contratto dati. Accettano invece un parametro ISurrogateSelector chiamato surrogateSelector (che esegue il mapping alla proprietà SurrogateSelector ). Si tratta di un meccanismo surrogato legacy.

  • Il costruttore accetta un parametro chiamato assemblyFormat di FormatterAssemblyStyle che esegue il mapping alla proprietà AssemblyFormat . Come illustrato in precedenza, ciò può essere utilizzato per migliorare le funzionalità di controllo delle versioni del serializzatore. È identico al meccanismo FormatterAssemblyStyle nella serializzazione SOAP o binaria.

  • Il costruttore accetta un parametro StreamingContext chiamato context che esegue il mapping alla proprietà Context . È possibile utilizzare questa funzionalità per passare informazioni nei tipi serializzati. Questo utilizzo è identico a quello del meccanismo StreamingContext utilizzato in altre classi System.Runtime.Serialization .

  • I metodi Serialize e Deserialize sono alias per i metodi WriteObject e ReadObject . Hanno la funzione di fornire un modello di programmazione più coerente con la serializzazione SOAP o binaria.

Per altre informazioni su queste funzionalità, vedere serializzazione binaria.

I formati XML utilizzati da NetDataContractSerializer e DataContractSerializer in genere non sono compatibili. Ciò significa che non è consentito eseguire la serializzazione con uno di questi serializzatori e la deserializzazione con l'altro.

Si noti inoltre che NetDataContractSerializer non restituisce il tipo completo di .NET Framework e il nome dell'assembly per ogni nodo nel grafico degli oggetti. Restituisce queste informazioni solo in caso di ambiguità. Ovvero, a livello dell'oggetto radice e per il qualsiasi caso polimorfico.

Vedi anche