Deserializing derived type using DataContractSerializer when derived type is not known beforehand
Asked Answered
C

2

5

In Assembly A:

[DataContract]    
        public class Base
        {
            [DataMember]
            public string SomeText { get; set; }
        }

In Assembly B:

internal class Helper
        {
           internal static Base Deserialize(string serializedInstanceOfTypeBase)
    {
                   DataContractSerializer serializer = new DataContractSerializer(typeof (Base));
                    XmlReader reader = XmlReader.Create(new StringReader(serializedInstanceOfTypeBase));
                    return (Base)serializer.ReadObject(reader);
    }
    }

In Assembly C:

[DataContract]    
        public class Derived : Base
        {
            [DataMember]
            public string SomeMoreText { get; set; }
        }

If I serialize an instance of type Derived and pass it to Helper.Deserialize() method, it fails with the SerializationException:

Error in line 1 position 2. Expecting element 'Base' from namespace 'http://schemas.datacontract.org/2004/07'.. Encountered 'Element' with name 'Derived', namespace 'http://schemas.datacontract.org/2004/07'.

How can I get rid of this issue?

I am aware of the KnownType attribute, but at the time of coding in assembly A and B, I am absolutely not aware of its derived types. So I cannot use that solution.

Design of my product is more complex which I cannot post here entirely. Helper.Desrialize() method just gets a string argument. There is no way (at present at least) for assembly A or B, to know about derived types of Base class, even at runtime.

Assembly B references assembly A. But A & B cannot reference assembly C.

I am using C# 4.0. It's ok if the solution you provide is NOT using DataContractSerializer.

Conspicuous answered 12/10, 2012 at 12:47 Comment(2)
I don't know about a out-of-the-box solution. I know in my experience when I had a wide variety of types, I would actually double-serialize my content with type information. That is, I would have a SerializedObject which would contain full type information (assembly name, full class name), along with its serialized XML string. My data transfer layer would strongly type itself against SerializedObject, grab a runtime reference to the type (say via Type.GetType), then deserialize the XML data accordingly via an XmlSerializer.Ellington
You mean 'Base' class is in 'Assembly A' and 'Derived' class is in 'Assembly C'? If this is so then I think this is the problem. The Data Contracts should be defined in same assembly. The DataContracts should not be splitted across assemblies.Mccreary
I
4

It looks like you need both:

  • Pass a collection of KnownTypes into your deserializer (as mentioned above)
  • Tell the deserializer not to check the type (use verifyObjectNameparameter):

    return (Base)serializer.ReadObject(reader, false);
    

see details here: http://msdn.microsoft.com/en-us/library/ms573850%28v=vs.110%29.aspx

Iconoclast answered 8/1, 2014 at 20:55 Comment(0)
T
3

Do you know the types at runtime ? If so, a simple approach might be just:

List<Type> knownTypes = ...; // now that you know what to expect
DataContractSerializer serializer = new DataContractSerializer(
    typeof(Base), knownTypes);
Tumefy answered 12/10, 2012 at 12:49 Comment(1)
Thanks for your answer. It's very helpful but I have added more details to the question. I should have added those details before. Note that Helper class is in different assembly and it's not public. Also, Deserialize method just gets any string value.Conspicuous

© 2022 - 2024 — McMap. All rights reserved.