XML 反序列化谜题
XML deserialisation puzzle
我对使用直接代码反序列化 XML 感到困惑,这些代码似乎非常忠实地遵循 msdn 文档,但没有产生预期的对象成员值:
给定以下 class 结构
[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;
}
和以下 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
以下代码(其中 xmlResponse 是一个包含上述 XML 的 XDocument 对象)生成一个 AddOrderResult 对象,当 XML 显然是 '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
}
这种略有不同的方法具有相同的结果:
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
}
在生成的反序列化 AddOrderResult 对象中,Order 属性(一个对象本身)具有所有正确的值;只有 xml 中的 ErrorMessage、Result 和 ResultStatus 值未正确反序列化。
我是犯了一个明显的错误,还是这是一个已知问题?问题出在反序列化代码、class 定义还是 XML 中?
您遇到的问题与命名空间有关。在您的 XML 中,ResultStatus
行使用 xmlns
属性标记有命名空间。因此,您需要在 DataContract
中使用此命名空间。如果您将 AddResult class 更改为:
[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;
}
您会发现 ResultStatus 被正确读取。
编辑:
这是一个独立的示例,显示了正在读入系统并正确填充的所有值。这包括对您在问题中遗漏的 classes 的最佳猜测。
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;
}
}
我对使用直接代码反序列化 XML 感到困惑,这些代码似乎非常忠实地遵循 msdn 文档,但没有产生预期的对象成员值:
给定以下 class 结构
[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;
}
和以下 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
以下代码(其中 xmlResponse 是一个包含上述 XML 的 XDocument 对象)生成一个 AddOrderResult 对象,当 XML 显然是 '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
}
这种略有不同的方法具有相同的结果:
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
}
在生成的反序列化 AddOrderResult 对象中,Order 属性(一个对象本身)具有所有正确的值;只有 xml 中的 ErrorMessage、Result 和 ResultStatus 值未正确反序列化。
我是犯了一个明显的错误,还是这是一个已知问题?问题出在反序列化代码、class 定义还是 XML 中?
您遇到的问题与命名空间有关。在您的 XML 中,ResultStatus
行使用 xmlns
属性标记有命名空间。因此,您需要在 DataContract
中使用此命名空间。如果您将 AddResult class 更改为:
[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;
}
您会发现 ResultStatus 被正确读取。
编辑:
这是一个独立的示例,显示了正在读入系统并正确填充的所有值。这包括对您在问题中遗漏的 classes 的最佳猜测。
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;
}
}