Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Atteint de JavaScriptite Aiguë [Cyril Durand]

Expert ASP.net Ajax et WCF, Cyril Durand parle dans son blog de point techniques sur ASP.net, ASP.net Ajax, JavaScript, WCF et .net en général. Cyril est également consultant indépendant, n'hésitez pas à le contacter pour de l'assistance sur vos projets

Actualités

  • Blog de Cyril DURAND, passionné de JavaScript, Ajax, ASP.net et tout ce qui touche au developpement Web Client-Side.

    N'hésitez pas à me contacter pour vos projets .net : architecture, accompagnement, formation, ...

    View Cyril Durand's profile on LinkedIn
    hit counters


    Expertise Commerce server et BizTalk

WCF : serialiser un objet non serialisable lorsque l'on n'a pas accès au type

Lorsqu'on utilise un service WCF, il se peut que l'on ne possède pas le contrôle des différents types que l'on transfère. Dans ce cas il est possible d'avoir des problèmes pour sérialiser, en effet, ne pouvant pas modifier le type, on ne peut pas rajouter des attributs utiles à la sérialisation, rajouter un constructeur vide, ... 
Ces problèmes surviennent quelques soit le binding utilisé, dans la suite de mon exemple j'utilise le netTcpBinding.

J'ai récemment été confronté à ce problème, après pas mal de recherche, j'ai trouvé une solution qui me convenait, celle-ci ne nécessite pas de réécrire une version simplifié de l'objet à transiter.

Pour cela j'ai créé une classe possédant une propriété du type de l'objet à transférer. Dans mon exemple, l'objet qui pose problème lors de la sérialisation est de type Query.

public class QueryEncapsulator{ public QueryEncapsulator() { } public QueryEncapsulator(Query q) { this.Query = q; } public Query Query { get; set; } }

Bien sur, cela ne suffit pas pour résoudre le problème, l'étape suivante est d'implémenter l'interface IXmlSerializable. Cette interface va nous permettre de personnaliser la sérialisation de cet objet, pour ne pas avoir de problème nous allons utiliser une sérialisation binaire via le BinaryFormatter puis écrire le binaire dans le XMLWriter en base64.

[Serializable] public class QueryEncapsulator : IXmlSerializable { public QueryEncapsulator() { } public QueryEncapsulator(Query q) { this.Query = q; } public Query Query { get; set; } public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(System.Xml.XmlReader reader) { BinaryFormatter formatter = new BinaryFormatter(); Byte[] b = new Byte[1024]; using (MemoryStream ms = new MemoryStream()) { if (!reader.Read()) throw new Exception("boom"); int i; while ((i = reader.ReadContentAsBase64(b, 0, b.Length)) > 0) { ms.Write(b, 0, i); } ms.Position = 0; Query obj = (Query)formatter.Deserialize(ms); this.Query = obj; } } public void WriteXml(System.Xml.XmlWriter writer) { using (MemoryStream ms = new MemoryStream()) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(ms, this.Query); Byte[] b = ms.ToArray(); writer.WriteBase64(b, 0, b.Length); } } }

A partir de là, nous pouvons transférer notre objet QueryEncapsulator à la place de notre objet Query.

Mais pourquoi cette astuce fonctionne ? En effet, pourquoi une sérialisation binaire via le BinaryFormatter fonctionne alors que lorsqu'on utilise le NetTcpBinding le message est transféré sous forme binaire.

[disclaimer:information non confirmé] D'après ce que j'ai compris, quelque soit le binding utilisé la sérialisation WCF se fait via le DataContractSerializer. Ce DataContractSerializer utilise en interne les mécanismes sous-jacent de la sérialisation XML afin de créer le graph de la sérialisation. Cela implique que l'on peut utiliser l'interface IXmlSerializable afin de personaliser la sérialisation.

Niveau performance, le surcout de cette astuce est négligeable par rapport à la machinerie WCF, dans mon cas, le surcout ne prend pas 1ms alors que le service met entre 5 et 30ms à répondre.

Posted: mardi 17 juin 2008 21:19 par cyril
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

VincentG a dit :

A vérifier, mais il me semble que si la classe à sérialiser n'a pas l'attribut [DataContract] alors ce n'est pas pas le DataContractSerializer .Net 3 qui va être utilisé mais le XmlSerializer .Net 2.

Dans ce cas il est donc logique que ton code soit pris en compte, ta classe étant [Serializable] et implémentant IXmlSerializable.

Il devrait d'ailleurs fonctionner avec des WS Soap asp.Net 1.1

NB : Plutot qu'un QueryEncapsulator, j'aurais bien vu un Encapsulator

<Query> ;)

# juin 18, 2008 09:23

cyril a dit :

hum,

Je vais essayer de vérifier ce que tu dis avec le [DataContract]. D'après ce que tu dis, si notre classe ne possède pas l'attribut DataContract, c'est du XML qui est ensuite converti en binaire ?

Pourtant il me semble que dans le stack trace, je vois DataContractSerializer.

Sinon pour le Encapsulator

<T> j'y ai aussi pensé en écrivant ce post :-)

# juin 18, 2008 11:03

RaptorXP a dit :

Attention, ce n'est pas parceque tu utilise un NetTcpBinding que tout sera serialize en binaire. Par exemple lorsque tu envoie un DataSet par WCF (c'est mal, je sais), c'est serialisé en XML (je crois) meme avec NetTcp

# juin 18, 2008 19:40

cyril a dit :

C'est ce que je suis en train de vérifier, ton propos est cohérent avec celui de Vincent, en fait le DataContractSerializer utiliserait une serialization binaire pour tous les objets décorés avec [DataContract] pour les autres il y aurait une sérialisation XML puis ensuite le binding prend le main, donc on retourne de nouveau sur du XML.

Bref ca semble un peu compliqué et bien usine à gaz. Si quelqu'un à des explications : je prend.

# juin 18, 2008 19:51

VincentG a dit :

J'ai vérifié, et contrairement a ce que je pensais, par défaut WCF utilise le DataContractSerializer.

Et ce indifféremment sur des DataContract, [Serializable] et IXmlSerializable...

cf. http://msdn.microsoft.com/en-us/library/ms733901.aspx

Sinon pour l'aspect binaire / xml je crois (a verifier bis ;) que la réponse est "encodage binaire xml", les deux donc, le xml serait optimisé les balises etant encodées et le contenu en clair sauf pour les champs binaires qui ne sont pas transformés en base 64.

NB qui m'incite a croire ca :

pulic sealed class DataContractSerializer : XmlObjectSerializer

J'ai pas trouvé de doc claire sur le sujet :(

Une piste : http://msdn.microsoft.com/en-us/library/ms735115.aspx

(la flemme de reflector le framework .Net ;)

Bonne nuit!

# juin 18, 2008 22:57

usingsystemnet a dit :

"Et ce indifféremment sur des DataContract, [Serializable] et IXmlSerializable..." --&gt; oui c'est effectivement le cas depuis le sp1 du 3.5 si je me trompe pas ce qui n'était pas le cas avant ou il fallait décorer ses entités avec l'attribut DataContract.

concernant la serialisation xml pour les point de communication orienté connexion c'est effectivement du xml encodé en binaire et pour le http de la serialisaison xml simple (sachant qu'on peut très bien faire du binary over http en faisant du custom binding). Pour les champs binaire, bien penser à utiliser le mtom comme format de message.

# juin 19, 2008 12:00

cyril a dit :

Le SP1 de .net 3.5 fait quelque chose à ce niveau là, mais je ne sais pas exactement quoi ni comment, je n'ai pas le SP1 de .net 3.5 sur ma machine, il faut que je me renseigne sur ces différentes nouveautés.

# juin 19, 2008 16:06

VincentG a dit :

Négatif, le sp1 du 3.5 n'y change rien c'est comme ca dès le 3 : Cf. http://msdn.microsoft.com/en-us/library/ms733901(VS.85).aspx

# juin 19, 2008 18:47

usingsystemnet a dit :

Visual Studio 2008 and .NET Framework 3.5 Service Pack 1 Beta Change

...

Expanding reach of DataContract Serializer by relaxing the need of having [DataContract]/ [DataMember] on types and by supporting an interoperable mechanism for dealing with object references.

...

--&gt;http://msdn.microsoft.com/en-us/vstudio/products/cc533447.aspx

# juin 19, 2008 20:18

shieldd a dit :

Bonjour,

j'aimerai une précision car il y a quelque chose qui me parait flou dans tout ça.

L'attribut [Serializable] sur ton encapsulator est seulement utile pour la serialisation avec BinarryFormatter et SoapFormatter,

quant à ton interface IXmlSerializable, il me semblait qu'elle etait seulement utile au XmlSerializer (et DataContractSerializer si je ne me trompe pas).

Je ne comprend pas pourquoi à la fois l'interface IXmlSerializer et l'attribut Serializable

serait utile à un serializer.

os : Utiliser le BinaryFormatter sur un objet (Query) implique quand même la contrainte que Query soit marqué Serializable, et que tout ses attributs le doit aussi, chose que l'on ne controle pas forcement.

La solution a ce type de probleme peut paraitre laborieuse, mais la web service factory préconise de faire un classe "Translator" qui sert a mapé entre tes objets du domaine non serializable, et les contrats de données.

# juin 20, 2008 18:23
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01

- SharePoint Online: Script PowerShell pour supprimer une colonne dans tous les sites d’une collection par Blog Technique de Romelard Fabrice le 11-27-2018, 18:01