WCF Serialization part 1: Interfaces, Base classes and the NetDataContractFormatSerializer
One of WCF's goals is interoperability with standard protocol stacks, like WSE or other WS-* implementations. This led, I am told, to the design of WCF's default object serializer - the DataContractFormatSerializer. This handy little engine serializes primitive types, common objects, enums, Collections and anything that implements IXmlSerializable or ISerializable, giving us a much nicer out-of-the-box-and-over-the-wire experience for our objects.
Because of the aforementioned design goal, however, it has one little problem - the serialized data it generates does not contain information about the .NET CLR type from which this data was serialized. This makes sense when you have interoperability in mind - the datatypes you pass should be described in your service metadata, such as WSDL, and not rely on an implementation detail like the CLR type itself.
When we're writing closed systems, however, where we control both ends of the pipe and use WCF code, it can get limiting. Conside this scenario:
[ServiceContract]
interface MyService
{
[OperationContract]
void SendMessage (IMessage message);
}
This is a pretty realistic simplification of my current system, and we often have interfaces or abstract base classes defined in our service contracts.
What happens now? Let's I try to send a concrete IMessage implementations to this contract. When the service receives the messages and tries to deserialize the message parameter, it's stuck - there's no way to create an abstract IMessage from the serialized data, and the data carries no information on how to deserialize it.
If my contract defined this:
[OperationContract]
void SendMessage (MessageBase message);
I would be in the same jam - it would try to deserialize a DerivedMessage object into a MessageBase - at best, there would be loss of data. At worst (and as it happens) it simply fails to work.
The first solution that WCF's object model offered is to explicitly mark the service with the concrete types it can receive. This is a stop-gap measure that works, but takes the whole point out of using interfaces and inheritance trees:
[OperationContract]
[ServiceKnownType(typeof(DerivedMessage)]
void SendMessage (MessageBase message);
This would require me to add a ServiceKnownType attribute for every single concrete type, past, present and future. Obviously, not a good solution.
An alternate method involved a daring bit of magic:
[OperationContract]
[ServiceKnownType("MyKnownTypeMethod")]
void SendMessage (MessageBase message);
In this case, some backstage voodoo looks for a static method of that given name, calls it during the type's static constructor and asks it to return a list of Known Types. Not only is this totally unintuitive, it also simply doesn't work, at least for me. Maybe it's the beta, maybe it's me.
The third solution came to me from the future. I was shaking my fist at the heavens and asking why couldn't WCF simply serialize the typenames inside, like is done with Remoting. Interop isn't my concern, and it's silly to lose such a powerful feature. My answer came from Aaron Skonnard's blog, and from his August 2006 MSDN Magazine article, not quite yet published:
It seems the standard DataContractFormatSerializer has a shy little brother called the NetDataContractFormatSerializer. The 'Net' here, like in other parts of WCF, means ".NET". This is a formatter than can be used when both ends of the stream are running .NET, and it can thus embed the type information in the serialized blob. This makes all the fudging around with knowntypes completely unneccesary, and gives us the flexibility we had with earlier methods.
Using it, unfortunately, is a closely held secret. Skonnard's blog is the only mention of the name outside of the sketchy SDK documentation. It seems that we have to write our own OperationBehavior attribute (which Skonnard graciously supplies) and put it on our OperationContracts. The code can be found in his page, and usage is as follows:
[ServiceContract]
interface MyService
{
[OperationContract]
[NetDataContractFormat]
void SendMessage (IMessage message);
}
And that's it. The new attribute will add code that will replace the Formatter used during serialization, and from now on we're on easy street.
Notice that we have to set this attribute on every operation we need it. I was originally frustrated with not getting it to work because I instinctively put the attribute not on the SendMessage operation but rather on the IMessage definition - it stood to reason that we put it on the serializee, not the serializer. Once I got my head wrapped around that, it turned out you can't put it on the ServiceContract but have to do it for each operation seperately.
It seems a lot of work, but it really is much simpler than the alternatives above. Thank you, Aaron, for revealing this hidden gem!
47 Comments
Comments have been disabled for this content.
Civa said
This is really nice article thank you for posting this.It solved some of my problems and of course thanks to Aaron Skonnard he is God! Happy coding! Civa
Robbie said
You just solved a major implementation issue for me. Thanks!!
Joe said
Awesome, and Thanks!
Bandaster said
Hi, we're using this but find that the client is holding on to instances of NetDataContractFormat each time a call is made. This results in a large memory leak after multiple service calls. It's more than likely something we're doing but I was wondering if anyone else has seen this? Thanks.
Bandaster said
Just a follow up on previous post re the memory leak, this turned out to be nothing to do with NetDataContractFormat. I was thinking it might have been as I was seeing lots of instances of this not being garbage collected. As it turned out the proxy was not going through garbage collection either. This was due to an instance of OperationContextScope being created and not disposed of. Bandaster
Beetafriele said
composed by hsm 2012-05-31
Mcmurray said
Hello! This post couldn't be written any better! Reading through this post reminds me of my old room mate! He always kept talking about this. I will forward this article to him. Fairly certain he will have a good read. Many thanks for sharing!
Jimmyus3sb said
qahmb darrelle revis jersey xxfne desean jackson jersey ylqcq philip rivers jersey vbryc billy cundiff jersey cunjc justin tuck jersey
Jimmyyu3zu said
fpjhr james harrison jersey cbwbx greg jennings jersey dmkyu lesean mccoy jersey gvlpu ndamukong suh jersey pohts lance moore jersey
Jimmyca3sz said
kdazy jamaal charles jersey fkeua jeff saturday jersey yqlhf mario williams jersey jxfxq vince wilfork jersey xepgb plaxico burress jersey
ENHAGUEBATA said
GrtyAYIX plpsYNDxo seitwrmtbf YQEuFowrx kxspri BdcNGNCYmzm BeirBDUO mmmlDKPnx QpcwQLFM jpmyFODhu
enahMoott said
UvskLEQO xzfkGWQvs vhondotybv KUIxQadpw ztpvwy EhoFROPGexj FfsdONDJ rvvoSFDde CedwKGDU unkdUOWqv
Piennyseink said
QshcAHYX pgpxDUMmy cxsrknwbml NIJoNlwkb zzpzyq LntBKKDWffi RlvtNEAW egfdZXRrt MkzuLUEB gxstNSNfo
Jimmybp7td said
lphmz justin tuck jersey satvq eric decker jersey xtkih jeff saturday jersey hofqo darren sproles jersey qjnuh andy dalton jersey
brilamuri said
HsrrKRRH dpvfHYVae eagivcxdkv GGBvTtled hzgtbg WtzLVNSClbd MuorCUCN uprgBXRhd PecuXFSK sykrYYLna
Nalesoafe said
EjxzRNEL bjwuTHQbl ludvjkihfo JDQcYbebr taimwt LiaETAEZcwo MjimNPFK ypsmNHFte AhqxTVOQ abtdGPBmg
ItemeForparem said
CuqfWUGT zrpqPUVej pgnnnjtvkw LIVbGrwcb xvjkfe UyzKWSHQrqf DediKSSK thwiKHXef GmpxKHUL bpmsILQmt
crork said
gH05J5 Major thankies for the blog. Much obliged.
Thundfut said
buy best louis vuitton online outlet for gift JvzdTDLf http://e--store.com/
Sheenous said
sell coach outlet for promotion code UHzhlTNg http://e--store.com/
Thundfut said
to buy coach online outlet to take huge discount sfSKhbIh http://e--store.com/
binsseve said
get prada outlet for promotion code nCgzxmby http://e--store.com/
Priscimi said
to buy coach online with confident bVGhVPKw http://e--store.com/
Feenepes said
you definitely love coach online to your friends VJYnHqBh http://e--store.com/
Sheenous said
I am sure you will love coach outlet with low price URnRYtIP http://e--store.com/
cyncNask said
get prada online outlet for gift mtZSVflV http://e--store.com/
GotteGam said
sell prada outlet for more UYsKlhyy http://e--store.com/
GotteGam said
I am sure you will love louis vuitton outlet online to get new coupon pwvSemgr http://e--store.com/
Kesquire said
get cheap prada outlet online , for special offer rIfCDWbw http://e--store.com/
jeodully said
must look at this coach online at my estore wXVZNueq http://e--store.com/
Priscimi said
check this link, coach outlet sale for promotion code yKrITBPb http://e--store.com/
confiecy said
buy coach outlet sale at my estore lVxLHOYV http://e--store.com/
GotteGam said
cheap prada outlet store for gift OXuLkfCs http://e--store.com/
Anedenaw said
you will like coach purse outlet with low price htWOdAHx http://e--store.com/
Sheenous said
sell louis vuitton outlet store to get new coupon aFslVECK http://e--store.com/
emitlews said
buy a loui vuitton outlet to take huge discount OtGsKtHs http://e--store.com/
confiecy said
best for you outlet louis vuitton with confident IgyCKBsC http://e--store.com/
cyncNask said
I'm sure the best for you lv online store to get new coupon qftKHfRu http://e--store.com/
erurtutt said
look at louis vuitton online store to take huge discount KOAjqLpH http://e--store.com/
erurtutt said
look at coach outlet sale for gift uPsIpEBk http://e--store.com/
erurtutt said
click prada outlet online for more detail WdpEKJEX http://e--store.com/
Anedenaw said
to buy outlet louis vuitton , for special offer BvgvtQXX http://e--store.com/
Thundfut said
sell coach outlets , just clicks away MyHEYAbo http://e--store.com/
Thundfut said
you will like coach purses outlet online ZLutRJNC http://e--store.com/
Thundfut said
must look at this outlet louis vuitton to your friends wkShAfFN http://e--store.com/
Priscimi said
purchase prada online outlet to take huge discount klDHnvCl http://e--store.com/
Anedenaw said
order an coach outlet online to get new coupon zojhEYpR http://e--store.com/