WebService, Serializzazione, dati nullabili e interop 1.x e 2.0

[English version]

Finalmente con la versione 2.0 del Framework la serializzaione ci darà la possibilità di inserire nei nostri xml dati nulli secondo gli standard xml, xsi:nil.Tale possibilità ci viene offerta dai nullable types. L'xml è ad oggi considerato il re dei formati di interoperazione tra sistemi eterogenei per tecnologia. Un possibile scenario del prossimo futuro potrebbe essere quello di avere il sistema server che espone servizi web implementati con la 2.0 e client implementati con la 1.x.  Ovviamente la cosa è possibilissima. Ma cosa succede se il server espone un nullable type? Client-side interpreta il wsdl correttamente e genera quindi senza problemi la classe proxy.. ovviamente non disponendo di nullable types nativi i dati nullabili verranno sostituiti con tipi non nullabili (esempio bool invece di bool?). Anche a runtime tutto sembra andare bene ma quando ci troviamo davanti il primo dato nullo ecco che il serialializer della 1.x non riesce a interpretarlo generando errore.

So già che per questo molti scenderanno in piazza dicendo che l'xml generato dalla 2.0 non è compatibile con quello della 1.x... in realtà è solo che il Serializer della 1.x ha meno potenzialità di quello della 2.0 - mi sembra il minino - e per questo occorre avere qualche attenzione in più. 

Come risolvere? I NullableTypes di Luka sono un ottima soluzione alla cosa! I NullableTypes implementano IXmlSerializable, hanno quindi una serializazione Xml personalizzata che è conforme alla serializzazione dei nullable type nativi della 2.0! Fantastiko! :-D Dopo avere generato la classe proxy con VS2003 occorre personalizzarla e sostituire i value type nullabili con i tipi nullabili di Luka :-D

L'interoperabilità vale anche al contrario. Un server web che espone servizi implementati con la 1.x può usare i NullableTypes per esporre dati nullabili; una applicazione client 2.0 che vuole consumare tali servizi può con VS2005 interpretare senza problemi il wsdl per generare la classe proxy. I tipi nullabili  non vengono però convertiti correttamente ma vengono mappati come XmlElement. Sarà però possibile modificare tale classe sostituendo gli XmlElement con i Nullable<T> corrispondenti ai tipi che devono mappare e il gioco è fatto! :-D

Buona interop a tutti! :-D

[Errata Corrige] Implementare IXmlSerializable

Come sempre dico "mai usare quello che non è documentato", ma a volte non mi ascolto :(. E infatti questo post per segnalare un _bug_/imprecisione quando ho parlato di CDATA e implementaizone dell'interfaccia IXmlSerializable: "Come ti serializzo in CDATA", e il tip  "Serializzare elementi CData implementando IXmlSerializable" (che provvederò a correggere dopo qualche ulteriore accertamento).

Il problema sta nell'implementazione del metodo di lettura "void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)". Sembra essere infatti necessario portare il reader sul prossimo nodo prima che il metodo si concluda. Se avete seguito il mio tip e il campo CDATA lo avete usato come ultimo elmento del vostro schema allora non dovreste avete avuto problemi. Se il campo CDATA è invece un elemento non ultimo del vostro schema è probabile che la deserializzazione vi abbia dato qualche problema.

L'implementazione di IXmlSerializable.ReadXml è da rivedere come segue:

 void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
 {
  this.Text = reader.ReadString();
  reader.Read();
 }

A parte per qualche sparuto - e poco descritto - esempio in rete (vedi "Customize XML Serialization using IXmlSerializable") non ho trovato alcuna documentazione sulla cosa e nemmeno reflector - per ora - mi ha saputo aiutare. I test mi hanno portato a tale conclusione.

[UPDATE 04-nov-2005]. Altra soluzione è quella di usare GetElementString che unisce il ReadString e il posizionamento sul successivo nodo.

 void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
 {
    this.Text = reader.ReadElementString();
 }
«novembre»
domlunmarmergiovensab
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910