1
votes

I have the following type:

[XmlRoot(Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace")]
public class Location
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Collection<int> DataSourceIds { get; set; }
}

I'm serializing a list of Locations to XML, resulting in the following:

<ArrayOfLocation xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MyNamespace">
    <Location>
        <DataSourceIds xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <d3p1:int>1</d3p1:int>
        </DataSourceIds>
        <Id>2</Id>
        <Name>First</Name>
    </Location>
    <Location>
        <DataSourceIds xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <d3p1:int>1</d3p1:int>
            <d3p1:int>2</d3p1:int>
            <d3p1:int>3</d3p1:int>
            <d3p1:int>4</d3p1:int>
        </DataSourceIds>
        <Id>1</Id>
        <Name>Second</Name>
    </Location>
</ArrayOfLocation>

I then try to deserialize this XML as follows:

        var rootAttribute = new XmlRootAttribute("ArrayOfLocation")
        {
            Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace"
        };

        var serializer = new XmlSerializer(typeof(Location[]), rootAttribute);
        using (var xmlReader = XmlReader.Create(new StreamReader(response.GetResponseStream())))
        {
            locations = (Location[])serializer.Deserialize(xmlReader);
        }

This returns a list of Location objects, with every property set correctly... except DataSourceIds, which remains empty. Why isn't XmlSerializer deserializing the array of integers?

1
Can you post the serialization code, please? - pepOS
ASP.NET Web Api takes care of the serialization. - Bas
Although I just realised that Web API uses DataContractSerializer by default, so that's probably part of the problem... - Bas

1 Answers

0
votes

Since it was serialized with DataContractSerializer, you can deserialize it like so:

[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace")]
public class Location
{
    [DataMember]
    public int Id { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public Collection<int> DataSourceIds { get; set; }
}

And then use it like:

        using (var xmlReader = XmlReader.Create(stream))
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(Location[]));
            var locations = (Location[])serializer.ReadObject(xmlReader);
            Debug.WriteLine(DataContractSerializerHelper.GetXml(locations, serializer)); // Debug check on re-serialization, remove when not needed.
        }

The XmlRoot declaration is ignored by DataContractSerializer.

Finally, a utility method for re-serializing to an XML string, for debugging purposes:

public static class DataContractSerializerHelper
{
    private static MemoryStream GenerateStreamFromString(string value)
    {
        return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
    }

    public static string GetXml<T>(T obj, DataContractSerializer serializer) where T : class
    {
        using (var textWriter = new StringWriter())
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.IndentChars = "    "; // For cosmetic purposes.
            using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
            {
                serializer.WriteObject(xmlWriter, obj);
            }
            return textWriter.ToString();
        }
    }

    public static string GetXml<T>(T obj) where T : class
    {
        DataContractSerializer serializer = new DataContractSerializer(typeof(T));
        return GetXml(obj, serializer);
    }
}