Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing derived type using DataContractSerializer when derived type is not known beforehand

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.

like image 575
Learner Avatar asked Oct 12 '12 12:10

Learner


People also ask

How to use DataContractSerializer c#?

To use the DataContractSerializer, first create an instance of a class and an object appropriate to writing or reading the format; for example, an instance of the XmlDictionaryWriter. Then call the WriteObject method to persist the data.

What is by serialization with respect to WCF?

The process forms a sequence of bytes into a logical object; this is called an encoding process. At runtime when WCF receives the logical message, it transforms them back into corresponding . Net objects. This process is called serialization.

How do you serialize an object in WCF?

This code constructs an instance of the DataContractSerializer that can be used only to serialize or deserialize instances of the Person class. DataContractSerializer dcs = new DataContractSerializer(typeof(Person)); // This can now be used to serialize/deserialize Person but not PurchaseOrder.


2 Answers

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

like image 192
TheKotlet Avatar answered Sep 20 '22 10:09

TheKotlet


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);
like image 25
Marc Gravell Avatar answered Sep 20 '22 10:09

Marc Gravell