Serializing Inheritance Chains With WCF
During a recent code review, I noticed that a colleague was sending me service entities from his WCF service with flags for the data type. This itself wasn’t so bothersome to me, but what did bother me was that the model he was sending back was violating one of the basic rules of object oriented programming: encapsulation (well, inheritence and abstraction, too) by mashing all of the data types into one type differentiated by a property.
Having worked extensively with XML serializers and XSD.exe generated code, I suggested that instead of mashing all of the objects into one definition — with all of the different properties — build one abstract definition and define a hierarchy of classes that inherit from the abstract class.
This worked out great since the family of objects all had a very obvious common base, but now the question turned to how to notify the runtime serialization engine to include the concrete types when returning abstract types from an operation.
I had imagined that the .NET 3.0 team would have made the process more “automagic” and use reflection to find inheriting classes instead of requiring the explicit declaration of inheriting classes. As I soon found out, such is not the case as my proxy classes didn’t include any of the inheriting classes; the proxy definition only contained the definition for the base class.
The answer is the KnownTypeAttribute which must be used to decorate the class definition of the base class (in my case, an abstract class). One attribute must be added for each inheriting type which must be serialized across the wire. For example:
1 2 3 4 5 6 7 8 9 |
<span style="font-family: Courier New;"><span style="color: #000000;">[DataContract]</span> <span style="color: #000000;">[KnownType(</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">(Invertebrates))]</span> <span style="color: #000000;">[KnownType(</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">(Vertebrates))]</span> <span style="color: #000000;">[KnownType(</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">(Mammal))]</span> <span style="color: #000000;">[KnownType(</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">(Reptile))]</span> <span style="color: #000000;">[KnownType(</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">(Human))]</span> <span style="color: #0000ff;">public abstract class </span><span style="color: #000000;">Animal {</span> <span style="color: #008000;">// Base class definition</span> <span style="color: #000000;">}</span></span> |
Notice that the entire hierarchy has to be “flattened” and included in the declaration for the root base type. The DataMemberAttribute only has to be applied once on any property in the base class.