Search code examples
c#xmldatacontractserializer

XML Deserializer issues with PortableRest and tvdb.com API response


I just tried to consume the response of a REST api call from tvdb.com calling this url: http://thetvdb.com/api/GetSeries.php?&seriesname=Homeland which gives me this XML:

<?xml version="1.0" encoding="UTF-8" ?>
<Data>
  <Series>
    <seriesid>247897</seriesid>
    <SeriesName>Homeland</SeriesName>
  </Series>
  <Series>
    <seriesid>84450</seriesid>
    <SeriesName>Homeland Security USA</SeriesName>
  </Series>
</Data>

I wanted to use the PortableRest library which has a generic async method to call the url and return an object of my classes. Under the hood PortableRest uses the DataContractSerializer which somehow has problems deserializing this XML properly to my object. I believe I missed some attributes, anyone an idea? This is what results...looking strange. The Content property comes from the async result.

The problem

These are my classes:

[DataContract(Namespace = "")]
public class Data
{
        [DataMember]
        public IEnumerable<Series> Series { get; set; } 
}

[DataContract(Namespace = "")]
public class Series
{
    [DataMember(Name = "SeriesName")]
    public string SeriesName { get; set; }
    [DataMember(Name = "seriesid")]
    public string SeriesId { get; set; }
}

var data = await restClient.SendAsync<Data>(request);

Thanks!


Solution

  • The issue here is that your Series list is in one-level format rather than two-level format, but DataContractSerializer does not support one-level formatting for lists. Instead, it only supports two-level formats like this:

    <Data xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <Series>
            <Series>
                <seriesid>247897</seriesid>
                <SeriesName>Homeland</SeriesName>
            </Series>
            <Series>
                ...
            </Series>
        </Series>
    </Data>
    

    Thus you need to deserialize the XML using the following classes:

    [CollectionDataContract(Name="Data", Namespace="")]
    public class SeriesList : List<Series>
    {
    }
    
    [DataContract(Namespace = "")]
    public class Series
    {
        [DataMember(Name = "seriesid", Order=0)]
        public string SeriesId { get; set; }
        [DataMember(Name = "SeriesName", Order=1)]
        public string SeriesName { get; set; }
    }
    

    And use it like:

    var list = await restClient.SendAsync<SeriesList>(request);
    var data = new Data { Series = list.ToList() };
    

    By the way, note the use of the DataMemberAttribute.Order property. Data contracts are sensitive to order thus it is necessary to inform the serializer the order in which child XML elements will appear.