Introduzione alla serializzazione XML

La serializzazione è il processo di conversione di un oggetto in un form che può essere immediatamente trasportato. È possibile, ad esempio, serializzare un oggetto e trasportarlo su Internet mediante HTTP tra un client e un server. La deserializzazione invece ricostruisce l'oggetto dal flusso.

La serializzazione XML serializza solo i valori delle proprietà e dei campi pubblici di un oggetto in un flusso XML e non include informazioni sul tipo. Se ad esempio si dispone di un oggetto Libro che esiste nello spazio dei nomi Biblioteca, non si ha la certezza che venga deserializzato in un oggetto dello stesso tipo.

Nota   La serializzazione XML non converte metodi, indicizzatori, campi privati o proprietà di sola lettura, ad eccezione degli insiemi di sola lettura. Per serializzare tutti i campi e le proprietà di un oggetto, pubblici e privati, utilizzare BinaryFormatter al posto della serializzazione XML.

La classe centrale nella serializzazione XML è la classe XmlSerializer e i metodi più importanti sono Serialize e Deserialize. Il flusso XML generato da XmlSerializer è conforme alla raccomandazione XML Schema Definition language (XSD) 1.0 del World Wide Web Consortium (www.w3.org). Inoltre i tipi di dati generati sono conformi al documento intitolato "XML Schema Part 2: Datatypes". (informazioni in lingua inglese)

I dati contenuti negli oggetti sono descritti tramite costrutti del linguaggio di programmazione come classi, campi, proprietà, tipi primitivi, matrici e anche linguaggio XML incorporato sotto forma di oggetti XmlElement o XmlAttribute. È possibile creare classi personalizzate, annotate con attributi, o utilizzare lo strumento di definizione di schemi XML per generare le classi basate su uno schema XML esistente.

Se si dispone di uno schema XML, sarà possibile eseguire il programma di definizione di schemi XSD per generare un insieme di classi con tipizzazione forte rispetto allo schema e annotate con attributi. Quando viene serializzata un'istanza di una classe del genere, il linguaggio XML generato aderisce allo schema XML. Se si possiede una classe del genere, è possibile programmare in un modello a oggetti facilmente manipolato con la certezza che il linguaggio XML generato sia conforme allo schema XML. Questa è un'alternativa all'utilizzo di altre classi in .NET Framework, quali XmlReader e XmlWriter, per analizzare e scrivere un flusso XML. Per ulteriori informazioni sull'utilizzo di queste classi, vedere Impiego di XML in .NET Framework. Le classi consentono di analizzare qualsiasi flusso XML. Utilizzare invece XmlSerializer quando si prevede che il flusso XML sia conforme a uno schema XML noto.

Gli attributi controllano il flusso XML generato dalla classe XmlSerializer consentendo di impostare lo spazio dei nomi XML, il nome dell'elemento, il nome dell'attributo e così via, del flusso XML. Per ulteriori informazioni su questi attributi e su come controllano la serializzazione XML, vedere Controllo della serializzazione XML mediante attributi. Per una tabella degli attributi utilizzati per controllare il linguaggio XML generato, vedere Attributi che controllano la serializzazione XML.

La classe XmlSerializer può effettuare un'ulteriore serializzazione di un oggetto e generare un flusso XML con codifica SOAP. Il linguaggio XML generato aderisce alla sezione 5 del documento del World Wide Web Consortium intitolato "Simple Object Access Protocol (SOAP) 1.1" (informazioni in lingua inglese). Per ulteriori informazioni sul processo, vedere Generazione di messaggi SOAP con la serializzazione XML. Per una tabella degli attributi che controllano il linguaggio XML generato, vedere Attributi che controllano la serializzazione con codifica SOAP.

La classe XmlSerializer genera i messaggi SOAP creati da, e passati ai servizi Web XML. Per controllare i messaggi SOAP, è possibile applicare gli attributi alle classi, valori restituiti, parametri e campi trovati in file del servizio Web XML, con estensione ASMX. È possibile utilizzare entrambi gli attributi indicati nelle sezioni "Attributi che controllano la serializzazione XML" e "Attributi che controllano la serializzazione con codifica SOAP" in quanto un servizio Web XML può utilizzare lo stile letterale o quello con codifica SOAP. Per ulteriori informazioni sull'utilizzo degli attributi per il controllo del linguaggio XML generato da un servizio Web XML, vedere Serializzazione XML con servizi Web XML. Per ulteriori informazioni su SOAP e sui servizi Web XML, vedere Personalizzazione di messaggi SOAP.

Protezione delle applicazioni XmlSerializer

Quando si crea un'applicazione in cui viene utilizzato l'XmlSerializer, è necessario conoscere i seguenti elementi e le relative implicazioni:

  • L'XmlSerializer consente di creare file C# (file CS) e di compilarli in file DLL nella directory denominata dalla variabile di ambiente TEMP. La serializzazione avviene tramite tali DLL.

    Il codice e le DLL sono vulnerabili a un processo non autorizzato in fase di creazione e compilazione. Quando si utilizza un computer su cui è in esecuzione Microsoft Windows NT 4.0 o versione successiva, due o più utenti potrebbero condividere la directory temp. La condivisione di una directory temp è pericolosa se (1) i due account dispongono di privilegi di protezione diversi e (2) l'account con i privilegi superiori esegue un'applicazione che utilizza l'XmlSerializer. In tal caso, un utente può violare la protezione del computer sostituendo il file CS o DLL compilato. Per risolvere il problema, assicurarsi sempre che ogni account del computer disponga di un proprio profilo. In questo modo, per impostazione predefinita, la variabile di ambiente TEMP consentirà di fare riferimento a una directory diversa per ogni account.

  • Qualora un utente non autorizzato invii un flusso continuo di dati XML a un server Web (attacco di tipo denial of service), l'XmlSerializer continuerà a elaborare i dati finché le risorse del computer diventeranno insufficienti.

    Questo tipo di attacco viene eliminato se si utilizza un computer su cui è in esecuzione IIS (Internet Information Services) e l'applicazione viene eseguita all'interno di IIS. IIS è dotato di un gate che non consentirà l'elaborazione di flussi più lunghi del valore impostato (4 KB per impostazione predefinita). Se si crea un'applicazione in cui non si utilizza IIS e in cui la deserializzazione viene eseguita con l'XmlSerializer, è necessario implementare un gate simile per evitare gli attacchi di tipo denial of service.

  • L'XmlSerializer consentirà di serializzare i dati e di eseguire qualsiasi codice tramite qualsiasi tipo assegnato.

    Un oggetto non autorizzato presenta due tipi di minaccia. È possibile che venga eseguito codice dannoso o che tale codice venga inserito nel file C# creato dall'XmlSerializer. Nel primo caso, se un oggetto non autorizzato cerca di eseguire una procedura in grado di distruggere le risorse, la protezione dall'accesso di codice eviterà qualsiasi tipo di danno. Nel secondo caso, esiste in teoria la possibilità che un oggetto non autorizzato inserisca il codice nel file C# creato dall'XmlSerializer. Sebbene questo problema sia stato esaminato con attenzione e la possibilità di questo tipo di attacco sia estremamente remota, è opportuno non serializzare mai i dati tramite un tipo sconosciuto e non attendibile.

  • I dati riservati serializzati possono essere vulnerabili.

    È possibile memorizzare i dati serializzati dall'XmlSerializer come file XML o altro archivio di dati. Se l'archivio di dati è disponibile per altri processi o è visibile su una Intranet o su Internet, i dati possono venire prelevati e utilizzati in modo non appropriato. Se, ad esempio, si crea un'applicazione in cui si serializzano ordini che includono numeri di carte di credito, i dati sono altamente riservati. Per evitare il furto di dati, proteggere sempre l'archivio dei dati e garantirne la riservatezza.

Serializzazione di una classe semplice

Nell'esempio che segue viene illustrata una classe semplice con un campo pubblico.

Public Class OrderForm
    Public OrderDate As DateTime
End Class
[C#]
public class OrderForm{
    public DateTime OrderDate;
}

Quando un'istanza di questa classe viene serializzata, potrebbe essere simile a quanto segue.

<OrderForm>
    <OrderDate>12/12/01</OrderDate>
</OrderForm>

Per ulteriori esempi di serializzazione, vedere Esempi di serializzazione XML.

Elementi serializzabili

Gli elementi che seguono possono essere serializzati utilizzando la classe XmLSerializer.

  • Proprietà di lettura/scrittura pubbliche e campi di classi pubbliche.
  • Classi che implementano ICollection o IEnumerable. Vengono serializzati solo gli insiemi, non le proprietà pubbliche.
  • Oggetti XmlElement.
  • Oggetti XmlNode.
  • Oggetti DataSet.

Serializzazione e deserializzazione di oggetti

Per serializzare un oggetto, creare prima l'oggetto da serializzare e impostarne le proprietà e i campi pubblici. Per effettuare questa operazione, è necessario determinare il formato del trasporto in cui archiviare il flusso XML: come flusso o come file. Se ad esempio il flusso XML deve essere salvato in formato permanente, creare un oggetto FileStream. Quando si deserializza un oggetto, il formato del trasporto determina se verrà creato un flusso o un oggetto file. Dopo avere determinato il formato del trasporto, è possibile chiamare i metodi Serialize o Deserialize, in base alle esigenze.

Per serializzare un oggetto

  1. Creare l'oggetto e impostarne le proprietà e i campi pubblici.

  2. Costruire una classe XmlSerializer utilizzando il tipo dell'oggetto. Per ulteriori informazioni, vedere i costruttori di classe XmlSerializer.

  3. Chiamare il metodo Serialize per generare un flusso XML o una rappresentazione di file delle proprietà e dei campi pubblici dell'oggetto. Nell'esempio riportato di seguito viene creato un file.

    Dim myObject As MySerializableClass = New MySerializableClass()
    ' Insert code to set properties and fields of the object.
    Dim mySerializer As XmlSerializer = New XmlSerializer(GetType(MySerializableClass))
    ' To write to a file, create a StreamWriter object.
    Dim myWriter As StreamWriter = New StreamWriter("myFileName.xml")
    mySerializer.Serialize(myWriter, myObject)
    
    [C#]
    MySerializableClass myObject = new MySerializableClass();
    // Insert code to set properties and fields of the object.
    XmlSerializer mySerializer = new 
    XmlSerializer(typeof(MySerializableClass));
    // To write to a file, create a StreamWriter object.
    StreamWriter myWriter = new StreamWriter("myFileName.xml");
    mySerializer.Serialize(myWriter, myObject);
    

Per deserializzare un oggetto

  1. Costruire un XmlSerializer utilizzando il tipo di oggetto da deserializzare.

  2. Chiamare il metodo Deserialize per produrre una replica dell'oggetto. Durante la deserializzazione, è necessario eseguire il cast dell'oggetto restituito nel tipo dell'originale, come viene illustrato nell'esempio che segue, in cui viene deserializzato l'oggetto in un file, sebbene la deserializzazione possa essere eseguita anche in un flusso.

    Dim myObject As MySerializableClass
    ' Constructs an instance of the XmlSerializer with the type
    ' of object that is being deserialized.
    Dim mySerializer As XmlSerializer = New XmlSerializer(GetType(MySerializableClass))
    ' To read the file, creates a FileStream.
    Dim myFileStream As FileStream = _
    New FileStream("myFileName.xml", FileMode.Open)
    ' Calls the Deserialize method and casts to the object type.
    myObject = CType( _
    mySerializer.Deserialize(myFileStream), MySerializableClass)
    [C#]
    MySerializableClass myObject;
    // Constructs an instance of the XmlSerializer with the type
    // of object that is being deserialized.
    XmlSerializer mySerializer = 
    new XmlSerializer(typeof(MySerializableClass));
    // To read the file, creates a FileStream.
    FileStream myFileStream = 
    new FileStream("myFileName.xml", FileMode.Open);
    // Calls the Deserialize method and casts to the object type.
    myObject = (MySerializableClass) 
    mySerializer.Deserialize(myFileStream)
    

Per ulteriori esempi di serializzazione XML, vedere Esempi di serializzazione XML.

Vantaggi dell'utilizzo della serializzazione XML

La classe XmlSerializer offre un controllo completo e flessibile quando si serializza un oggetto come XML. Se si crea un servizio Web XML, sarà possibile applicare gli attributi che controllano la serializzazione a classi e membri per garantire che l'output XML sia conforme a uno schema specifico.

XmlSerializer, ad esempio, consente di:

  • Specificare se un campo o una proprietà deve essere codificata come attributo o elemento.
  • Specificare uno spazio dei nomi XML da utilizzare.
  • Specificare il nome di un elemento o attributo se il nome di un campo o di una proprietà non è corretto.

Un altro vantaggio della serializzazione XML è rappresentato dal fatto che non ci sono vincoli sulle applicazioni sviluppate, purché il flusso XML generato sia conforme a un determinato schema. Gli schemi utilizzati per descrivere libri, ad esempio, contengono un titolo, un autore, un editore e un elemento del numero ISBN. È possibile sviluppare un'applicazione che elabora i dati XML nel modo desiderato, ad esempio come un ordine o un inventario di libri. Nell'uno o nell'altro caso l'unico requisito è che il flusso XML sia conforme allo schema XSD (XML Schema Definition) specificato.

Considerazioni sulla serializzazione XML

Durante l'utilizzo della classe XmLSerializer è necessario tenere conto di quanto segue:

  • I dati serializzati contengono solo i dati stessi e la struttura delle classi. L'identità del tipo e le informazioni del codice assembly non vengono incluse.
  • È possibile serializzare solo le proprietà e i campi pubblici. Per serializzare dati non pubblici, utilizzare la classe BinaryFormatter anziché la serializzazione XML.
  • Una classe deve avere un costruttore predefinito serializzabile da XmlSerializer.
  • I metodi non possono essere serializzati.
  • XmlSerializer può elaborare classi che implementano IEnumerable o ICollection in modo diverso se rispondono a determinati requisiti. Una classe che implementa IEnumerable deve implementare un metodo Add pubblico che accetta un solo parametro. Il parametro del metodo Add deve essere coerente (polimorfico) con il tipo restituito dalla proprietà Enumerator.Current restituita dal metodo GetEnumerator. Una classe che implementa ICollection oltre a IEnumerable (come CollectionBase) deve avere una proprietà indicizzata Item pubblica (un indexer in C#) che accetta un valore integer e deve disporre di una proprietà Count pubblica di tipo integer. Il parametro passato al metodo Add deve essere dello stesso tipo di quello restituito dalla proprietà Item o del tipo di una delle classi base. Per le classi che implementano ICollection, i valori da serializzare verranno recuperati dalla proprietà Item indicizzata e non chiamando GetEnumerator. Si noti inoltre che le proprietà e i campi pubblici non saranno serializzati, con l'eccezione dei campi pubblici che restituiscono un'altra classe dell'insieme, una che implementa ICollection. Per un esempio, vedere Esempi di serializzazione XML.

Associazione dei tipi di dati XSD

Nel documento "XML Schema Part 2: Datatypes" del World Wide Web Consortium (www.w3.org) vengono specificati i tipi di dati semplici consentiti in uno schema del linguaggio XSD (XML Schema Definition) (informazioni in lingua inglese). Per molti di essi, ad esempio int e decimal, esiste un tipo di dati corrispondente in .NET Framework. Tuttavia alcuni dati XML, tra cui NMTOKEN, non hanno un corrispondente in .NET Framework. In questi casi, se si utilizza lo strumento di definizione di schemi XML (Xsd.exe) per generare classi da uno schema, un attributo appropriato verrà applicato a un membro di tipo stringa e la rispettiva proprietà DataType verrà impostata sul nome del tipo di dati XML. Se, ad esempio, uno schema contiene un elemento denominato "MyToken" con il tipo di dati XML NMTOKEN, la classe generata potrebbe contenere un membro, come viene illustrato nell'esempio che segue.

<XmlElement(DataType:="NMTOKEN")>
Public MyToken As String
[C#]
[XmlElement(DataType = "NMTOKEN")]
public string MyToken;

Analogamente, se si crea una classe che deve essere conforme a uno specifico schema XML (XSD), sarà necessario applicare l'attributo appropriato e impostarne la proprietà sul nome del tipo di dati XML desiderato.

Per un elenco completo di associazioni di dati, vedere la proprietà DataType per una qualsiasi delle seguenti classi di attributi: SoapAttributeAttribute, SoapElementAttribute, XmlArrayItemAttribute, XmlAttributeAttribute, XmlElementAttribute o XmlRootAttribute.

Vedere anche

Serializzazione XML e SOAP | XMLSerializer.Serialize | BinaryFormatter | Serializzazione binaria | Serializzazione di oggetti | XmlSerializer | FileStream | Esempi di serializzazione XML