Thursday, May 5, 2011

Having DataContractSerializer serialize the same class in two different ways?

I'm using the DataContractSerializer to serialize an objects properties and fields marked with DataMember attributes to xml.

Now a have another use case for the same class, where I need to serialize other properties and other fields.

Are there a way to add "another DataMemberAttribute" that can be used for my other serialization scenario?

From stackoverflow
  • No, basically.

    If you want to use the existing DataContractSerializer, you'll have to maintain a second version of the DTO class and convert the data between them.

    Options if you are writing your own serialization code:

    • declare your own [DataMember]-style attribute(s) and interpret them at runtime in your own serialization code
    • use a "buddy class"
    • use external metadata (such as a file)
    • use code-based configuration (i.e. via a DSL)

    In reality, I expect the first will be the simplest choice.

    asgerhallas : Thanks for the reply! Writing my own serialization code could be an option, but I really wouldn't know where to start - I'm using both DataContractSurrogate and are preserving references, and it seems like it takes some effort to "simulate" the behavior of the DataContractSerializer. Is there a way to write one based on the existing DataContractSerializer or are there links to similar solutions that your know of?
    Darrel Miller : The whole set of built in serialization techniques are such a tease. They look like they do what you want right up until you try and do something useful with them. I actually prefer the XAML serialization format because at least it does pretend to be anything other a XML based format of an object graph.
    asgerhallas : @Darrel Miller: Thanks for the pointer to XAML serialization format. I will check that out.
  • There is a way to do it, but it's an ugly hack.

    The DataContractSerializer can serialize objects that implement the IXmlSerializable interface. You could implement the interface and create your own ReadXml(XmlReader reader) and WriteXml(XmlWriter writer) methods that could serialize the object in different ways.

    Note that you'd have to have a flag embedded within the class itself to determine which way to serialize the object. (There's no way to tell the DataContractSerializer which mode to use, so the flag has to be contained in the object itself.)

    A second version of the DTO class, as @Marc suggests, would be much cleaner.

  • In a similar scenario in the past, we've taken an Object Oriented approach, and created a new class that extends from the main class. To help you achieve inhertience with the DataContractSerializer, check out KnownTypeAttribute

    In one of your comments to your question,

    If the same class is implementing multiple interfaces, certain data elements may be relevant to only one of the interfaces.

    If that is the case in your scenario, then perhaps your Data Service Contracts should be exposing just the Interfaces, and not the Class?

    For example, if you have a class like:

    [DataContract]
    public class DataObject : IRed, IBlue
    

    then rather than have your operation contract expose DataObject, you have two operation contracts one for IRed and one for IBlue. This eliminates the need for custom serialization code.

    asgerhallas : I think you are very right about that last point. The only downside to it, is that there will be a lot of duplicate "declaration" of properties in the interfaces, as most of the properties are serialized in both situations.
    Scott Ferguson : Ah well, duplicate declarations are no big deal... it's not the same as duplicate code logic, in my view.
    asgerhallas : I agree! But it is kind of tedious keeping them in sync... but well the compiler will of course help me there, and I shouldn't be so lazy :)

0 comments:

Post a Comment