knurd nerd
knurd nerd

Reputation: 324

DataContract serializer doesn't work for similar types

I have an application where I need to use the data contract serializer for different, but similar types:

On request from Scrobi, here's a full model example:

[DataContract]
public class Model
{
    public Model()
    {
        List = new List<int>(new[] {1, 2, 3});
        Collection = new Collection<int>(new[] {4, 5, 6});
        Array = new[] {7, 8, 9};
    }

    [DataMember]
    public object List { get; set; }

    [DataMember]
    public object Collection { get; set; }

    [DataMember]
    public object Array { get; set; }

    public string SerializeMe()
    {
        var serializer = new DataContractSerializer(typeof(Model), GetKnownTypes());

        using (var stream = new MemoryStream())
        {
            serializer.WriteObject(stream, this); // exception

            return Encoding.UTF8.GetString(stream.GetBuffer());
        }
    }

    public static Type[] GetKnownTypes()
    {
        return new[]
        {
            typeof(List<int>),
            typeof(Collection<int>), // error
            typeof(int[]) // error
        };
    }
}

The problem is: I can't add the generic List, Collection and the array at the same time, because all of them use the same data contract.

When I only use one of the collection types, I am unable to serialize the other ones, because they are unknown (the data contract is present, but for the other type). And yes, the fields must be objects to make this work for my case (and in the real application, I cannot add attributes to them).

It is very impractical in the application I write to only use one of the types, as it is a kind of development environment and the developer can choose the type freely.

Is there any workaround against this limitation of the data contract serializer?

Thanks,

Upvotes: 0

Views: 400

Answers (1)

Scrobi
Scrobi

Reputation: 1215

I have a partial answer but for some reason when testing the Collection<int> throws an error when deserialising. Maybe you can work with this to find a full solution.

I created a DataContractResolver allowing you to override the xsi:type There is some documentation here

public class MyResolver : DataContractResolver
{
    public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
    {
        string name = string.Empty;
        bool isFound = false;
        if (type.Name == "Int32[]")
        {
            name = "IntArray";
            isFound = true;
        }
        if (type.Name.Contains("List") && type.FullName.Contains("Int")) //find List<int>
        {
            name = "IntList";
            isFound = true;
        }
        if (type.Name.Contains("Collection") && type.FullName.Contains("Int")) //find Collection<int> 
        {
            name = "IntCollection";
            isFound = true;
        }

        if (isFound)
        {
            XmlDictionary dictionary = new XmlDictionary();
            typeName = dictionary.Add(name);
            typeNamespace = dictionary.Add("http://tempuri.com");
            return true;
        }

        return knownTypeResolver.TryResolveType(type, declaredType, knownTypeResolver, out typeName, out typeNamespace);
    }

    public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
    {
        if (typeName == "IntArray" )
        {
            return typeof(int[]);
        }
        if (typeName == "IntList")
        {
            return typeof(List<int>);
        }
        if (typeName == "IntCollection")
        {
            return typeof(Collection<int>);
        }


        return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null);
    }
}

You then don't need your GetKnownTypes() and create the DataContractSerializer like this:

var serializer = new DataContractSerializer(typeof(Model),null, int.MaxValue, false, false,null, new MyResolver());

Hope this somewhat helps.

Upvotes: 1

Related Questions