XML deserialisation puzzle

65 views Asked by At

I have a puzzle with deserialising XML using straight forward code that seems to follow the msdn documentation quite faithfully, but which is not yielding the expected object member values:

Given the following class structure

[DataContract(Namespace = "")]
public class AddResult
{
    [DataMember()]
    public string ErrorMessage;
    [DataMember()]
    public bool ResultStatus;
    [DataMember()]
    public string Result;
}

[DataContract(Namespace = "")]
public class AddOrderResult : AddResult
{

    [DataMember()]
    public Order Order;
}

and the following XML:

<AddOrderResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <ErrorMessage i:nil="true" xmlns="http://schemas.datacontract.org/2004/07/appulsive.Intertek.LIMSService" />
  <Result i:nil="true" xmlns="http://schemas.datacontract.org/2004/07/appulsive.Intertek.LIMSService" />
  <ResultStatus xmlns="http://schemas.datacontract.org/2004/07/appulsive.Intertek.LIMSService">true</ResultStatus>
  <Order>
    <Kto>10025</Kto>
    <LIMSIdentifier>12345</LIMSIdentifier>
    <Matchcode>test order 1</Matchcode>
    <OfficeLineHandle>547864</OfficeLineHandle>
    <OverruleCreditCheck>true</OverruleCreditCheck>
  </Order>
</AddOrderResult

the following code (where xmlResponse is an XDocument object containing the above XML) produces an AddOrderResult object with the ResultStatus property set to FALSE when the value in the XML is clearly 'true':

     AddOrderResult res;
     using (MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(xmlResponse.ToString())))
    {
        stream.Position = 0;
        XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
        DataContractSerializer ser = new DataContractSerializer(typeof(AddOrderResult),new Type[] {typeof(AddResult)});
        res = (AddOrderResult)ser.ReadObject(reader,true);
        resultStatus = res.ResultStatus; //<-this should be true, but is actually false
    }

This slightly different approach has the same outcome:

            AddOrderResult res;
            using (MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(xmlResponse.ToString())))
            {
                stream.Position = 0;
                XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
                XmlSerializer ser = new XmlSerializer(typeof(AddOrderResult),new Type[] {typeof(AddResult)});
                res = (AddOrderResult)ser.Deserialize(reader);
                resultStatus = res.ResultStatus; //<-this should be true, but is actually false
            }

In the resulting deserialized AddOrderResult object the Order property (an object itself) has all the correct values; it is only the ErrorMessage, Result and ResultStatus values in the xml that are not correctly deserialized.

Am I making an obvious mistake, or is this a known issue? Is the problem in the deserialization code, the class defninitions or the XML?

1

There are 1 answers

3
Wolfwyrd On BEST ANSWER

The issue you have is down to the Namespace. In your XML the ResultStatus line is tagged with a namespace using the xmlns attribute. As such you need to use this namespace in your DataContract. If you change your AddResult class to look like:

[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/appulsive.Intertek.LIMSService")]
public class AddResult
{
    [DataMember()]
    public string ErrorMessage;
    [DataMember()]
    public bool ResultStatus;
    [DataMember()]
    public string Result;
}

You'll find that ResultStatus gets read correctly.

EDIT:

Here's a self-contained example that shows the values being read into the system and all populating correctly. This includes a best guess at the classes that you've missed in the question.

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;

namespace SO_AddOrder
{
    class Program
    {
        const string Xml = @"<AddOrderResult xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
  <ErrorMessage i:nil=""true"" xmlns=""http://schemas.datacontract.org/2004/07/appulsive.Intertek.LIMSService"" />
  <Result i:nil=""true"" xmlns=""http://schemas.datacontract.org/2004/07/appulsive.Intertek.LIMSService"" />
  <ResultStatus xmlns=""http://schemas.datacontract.org/2004/07/appulsive.Intertek.LIMSService"">true</ResultStatus>
  <Order>
    <Kto>10025</Kto>
    <LIMSIdentifier>12345</LIMSIdentifier>
    <Matchcode>test order 1</Matchcode>
    <OfficeLineHandle>547864</OfficeLineHandle>
    <OverruleCreditCheck>true</OverruleCreditCheck>
  </Order>
</AddOrderResult>";

        static void Main(string[] args)
        {
            AddOrderResult res;
            using (MemoryStream stream = new MemoryStream(Encoding.Default.GetBytes(Xml)))
            {
                stream.Position = 0;
                XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
                DataContractSerializer ser = new DataContractSerializer(typeof(AddOrderResult), new Type[] { typeof(AddResult) });
                res = (AddOrderResult)ser.ReadObject(reader, true);
            }
            Console.WriteLine(res.ResultStatus);
        }
    }



    // Define other methods and classes here
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/appulsive.Intertek.LIMSService")]
public class AddResult
{
    [DataMember()]
    public string ErrorMessage;
    [DataMember()]
    public bool ResultStatus;
    [DataMember()]
    public string Result;
}

[DataContract(Namespace = "")]
public class AddOrderResult : AddResult
{

    [DataMember()]
    public Order Order;
}

[DataContract(Namespace = "")]
public class Order
{

    [DataMember()] 
    public int Kto;


    [DataMember()]
    public string LIMSIdentifier;

    [DataMember()]
    public string Matchcode;

    [DataMember()]
    public int OfficeLineHandle;

    [DataMember()]
    public bool OverruleCreditCheck;
}
}