Firstly, this post has been prompted by an MSDN Magazine article by renowned brain-box, Juval Lowy: Data Contract Inheritance. Having recently been forced to resort to the [KnownType] attribute on a WCF data contract, and having been slightly confused as to why (not to mention uncomfortable with having a data contract base class now coupled to its subclasses) the article has proved most illuminating.
For my own benefit here are a few choice bits from the article (my bold).
What’s the problem?
“Unlike traditional object orientation or the classic CLR programming model, WCF passes all operation parameters by value, not by reference… The parameters are packaged in the WCF message and transferred to the service, where they are then deserialized to local references for the service operation to work with…
… With multitier applications, marshaling the parameters by value works better than by reference because any layer in the architecture is at liberty to provide its own interpretation to the behavior behind the data contract. Marshaling by value also enables remote calls, interoperability, queued calls and long-running workflows.
… If you do pass a subclass reference to a service operation that expects a base class reference, how would WCF know to serialize into the message the derived class portion?”
What does [KnownType] do?
“When the client passes a data contract that uses a known type declaration, the WCF message formatter tests the type (akin to using the is operator) and sees if it’s the expected known type. If so, it serializes the parameter as the subclass rather than the base class…
The WCF formatter uses reflection to collect all the known types of the data contracts, then examines the provided parameter to see if it’s of any of the known types…
… Because the KnownType attribute may be too broad in scope, WCF also provides ServiceKnownTypeAttribute, which you can apply on a specific operation or on a specific contract.”
.Net 4 to the rescue
“To alleviate the problem, in the .NET Framework 4 WCF introduced a way of resolving the known types at run time. This programmatic technique, called data contract resolvers, is the most powerful option because you can extend it to completely automate dealing with the known type issues. In essence, you’re given a chance to intercept the operation’s attempt to serialize and deserialize parameters and resolve the known types at run time both on the client and service sides.”