XmlSerializer 和 xsi:反序列化
XmlSerializer and xsi: deserialization
由于 xsi:type="p:OUTPUT-HEADER" 属性,我很难尝试反序列化对应于 WCF SOAP 服务 FAULT 详细信息部分的这段 XML 代码:
<p:OUTPUT-HEADER xsi:type="p:OUTPUT-HEADER" xmlns:p="http://aaa.bbb.ccc/v2" xmlns:ns0="http://aaa.bbb.ccc/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<FAULT>
<p:COD-ERROR>2951</p:COD-ERROR>
<p:COD-SEV>8</p:COD-SEV>
<p:MSG-ERROR>Error message</p:MSG-ERROR>
</FAULT>
<CNL-OUT>xxx</CNL-OUT>
</p:OUTPUT-HEADER>
这些是我正在使用的类:
[XmlInclude(typeof(OutputHeader))]
public abstract class FaultDetail
{
[XmlElement(ElementName = "FAULT", Namespace = "")]
public Fault FaultSection{ get; set; }
[XmlElement(ElementName = "CNL-OUT", Namespace = "")]
public string ClnOut{ get; set; }
}
[XmlRoot(ElementName = "OUTPUT-HEADER", Namespace = "http://aaa.bbb.ccc/v2")]
public class OutputHeader : FaultDetail
{
}
public class Fault
{
[XmlElement(ElementName = "COD-ERROR")]
public int CodigoError { get; set; }
[XmlElement(ElementName = "COD-SEV")]
public int Severidad { get; set; }
[XmlElement(ElementName = "MSG-ERROR")]
public string Mensaje { get; set; }
}
XmlSerializer:
XmlSerializer x = new XmlSerializer(typeof(OutputHeader));
以及我在调用反序列化方法时遇到的错误:
“无法识别指定的类型:名称
='OUTPUT-HEADER',命名空间='http://aaa.bbb.ccc/v2',位于 ."
是否可以修饰 类 以正确反序列化此 XML?
非常感谢任何想法,谢谢!
而不是 XmlSerializer
,您似乎必须使用 DataContractSerializer
to deserialize this XML. This serializer is the default serializer for WCF,因此您只需要删除指定使用 XmlSerializer
的代码。
按如下方式设计类型:
[DataContract(Namespace = "")]
public abstract class OutputHeaderBase
{
[DataMember(Name = "FAULT", Order = 1)]
public Fault FaultSection { get; set; }
[DataMember(Name = "CNL-OUT", Order = 2)]
public string ClnOut { get; set; }
}
[DataContract(Name = "OUTPUT-HEADER", Namespace = "http://aaa.bbb.ccc/v2")]
public class OutputHeader : OutputHeaderBase
{
}
[DataContract(Name = "FAULT", Namespace = "http://aaa.bbb.ccc/v2")]
public class Fault
{
[DataMember(Name = "COD-ERROR", Order = 1)]
public int CodigoError { get; set; }
[DataMember(Name = "COD-SEV", Order = 2)]
public int Severidad { get; set; }
[DataMember(Name = "MSG-ERROR", Order = 3)]
public string Mensaje { get; set; }
}
然后将您的操作合约声明为返回(或接受)OutputHeader
类型的对象(不是OutputHeaderBase
)。
最终通过删除 [XmlSerializerFormat]
from your service and/or operation contract, and you should be all set. For details of switching see Using the XmlSerializer Class
切换回数据合同序列化
(另请注意 Fault
的属性需要放入正确的命名空间中。)
为什么这样行得通?
"xsi:type"
attribute is a w3c standard attribute that allows an element to explicitly assert its type. Both XmlSerializer
and DataContractSerializer
在序列化多态类型时使用此属性来传达实际类型信息。但是,以下元素:
<p:OUTPUT-HEADER
xsi:type="p:OUTPUT-HEADER"
xmlns:p="http://aaa.bbb.ccc/v2"
xmlns:ns0="http://aaa.bbb.ccc/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
</p:OUTPUT-HEADER>
在命名空间 http://aaa.bbb.ccc/v2
中具有基本类型 OUTPUT-HEADER
并且在命名空间 http://aaa.bbb.ccc/v2
中具有子类型 OUTPUT-HEADER
-- 即类型和子类型信息相同,因此 xsi:type
属性是多余的。
但是,如果它是多余的,它应该是无害的,对吧?您可以为 XmlSerializer
设计一个类型层次结构,如下所示:
[XmlRoot(ElementName = "OUTPUT-HEADER", Namespace = "http://aaa.bbb.ccc/v2")]
[XmlInclude(typeof(OutputHeaderSubclass))] // Artificial subtype to trigger handling of the `xsi:type` attribute.
[XmlInclude(typeof(OutputHeader))]
public class OutputHeader
{
[XmlElement(ElementName = "FAULT", Namespace = "")]
public Fault FaultSection { get; set; }
[XmlElement(ElementName = "CNL-OUT", Namespace = "")]
public string ClnOut { get; set; }
}
[XmlRoot(ElementName = "OUTPUT-HEADER-SUBCLASS", Namespace = "http://aaa.bbb.ccc/v2")]
public class OutputHeaderSubclass : OutputHeader
{
}
然后反序列化为 OutputHeader
可能会很好。不幸的是,事实并非如此。 XmlSerializer
为冗余属性抛出异常而不是处理它。相反,DataContractSerializer
没有,所以这就是要使用的。
由于 xsi:type="p:OUTPUT-HEADER" 属性,我很难尝试反序列化对应于 WCF SOAP 服务 FAULT 详细信息部分的这段 XML 代码:
<p:OUTPUT-HEADER xsi:type="p:OUTPUT-HEADER" xmlns:p="http://aaa.bbb.ccc/v2" xmlns:ns0="http://aaa.bbb.ccc/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<FAULT>
<p:COD-ERROR>2951</p:COD-ERROR>
<p:COD-SEV>8</p:COD-SEV>
<p:MSG-ERROR>Error message</p:MSG-ERROR>
</FAULT>
<CNL-OUT>xxx</CNL-OUT>
</p:OUTPUT-HEADER>
这些是我正在使用的类:
[XmlInclude(typeof(OutputHeader))]
public abstract class FaultDetail
{
[XmlElement(ElementName = "FAULT", Namespace = "")]
public Fault FaultSection{ get; set; }
[XmlElement(ElementName = "CNL-OUT", Namespace = "")]
public string ClnOut{ get; set; }
}
[XmlRoot(ElementName = "OUTPUT-HEADER", Namespace = "http://aaa.bbb.ccc/v2")]
public class OutputHeader : FaultDetail
{
}
public class Fault
{
[XmlElement(ElementName = "COD-ERROR")]
public int CodigoError { get; set; }
[XmlElement(ElementName = "COD-SEV")]
public int Severidad { get; set; }
[XmlElement(ElementName = "MSG-ERROR")]
public string Mensaje { get; set; }
}
XmlSerializer:
XmlSerializer x = new XmlSerializer(typeof(OutputHeader));
以及我在调用反序列化方法时遇到的错误:
“无法识别指定的类型:名称
='OUTPUT-HEADER',命名空间='http://aaa.bbb.ccc/v2',位于
是否可以修饰 类 以正确反序列化此 XML? 非常感谢任何想法,谢谢!
而不是 XmlSerializer
,您似乎必须使用 DataContractSerializer
to deserialize this XML. This serializer is the default serializer for WCF,因此您只需要删除指定使用 XmlSerializer
的代码。
按如下方式设计类型:
[DataContract(Namespace = "")]
public abstract class OutputHeaderBase
{
[DataMember(Name = "FAULT", Order = 1)]
public Fault FaultSection { get; set; }
[DataMember(Name = "CNL-OUT", Order = 2)]
public string ClnOut { get; set; }
}
[DataContract(Name = "OUTPUT-HEADER", Namespace = "http://aaa.bbb.ccc/v2")]
public class OutputHeader : OutputHeaderBase
{
}
[DataContract(Name = "FAULT", Namespace = "http://aaa.bbb.ccc/v2")]
public class Fault
{
[DataMember(Name = "COD-ERROR", Order = 1)]
public int CodigoError { get; set; }
[DataMember(Name = "COD-SEV", Order = 2)]
public int Severidad { get; set; }
[DataMember(Name = "MSG-ERROR", Order = 3)]
public string Mensaje { get; set; }
}
然后将您的操作合约声明为返回(或接受)OutputHeader
类型的对象(不是OutputHeaderBase
)。
最终通过删除 [XmlSerializerFormat]
from your service and/or operation contract, and you should be all set. For details of switching see Using the XmlSerializer Class
(另请注意 Fault
的属性需要放入正确的命名空间中。)
为什么这样行得通?
"xsi:type"
attribute is a w3c standard attribute that allows an element to explicitly assert its type. Both XmlSerializer
and DataContractSerializer
在序列化多态类型时使用此属性来传达实际类型信息。但是,以下元素:
<p:OUTPUT-HEADER
xsi:type="p:OUTPUT-HEADER"
xmlns:p="http://aaa.bbb.ccc/v2"
xmlns:ns0="http://aaa.bbb.ccc/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
</p:OUTPUT-HEADER>
在命名空间 http://aaa.bbb.ccc/v2
中具有基本类型 OUTPUT-HEADER
并且在命名空间 http://aaa.bbb.ccc/v2
中具有子类型 OUTPUT-HEADER
-- 即类型和子类型信息相同,因此 xsi:type
属性是多余的。
但是,如果它是多余的,它应该是无害的,对吧?您可以为 XmlSerializer
设计一个类型层次结构,如下所示:
[XmlRoot(ElementName = "OUTPUT-HEADER", Namespace = "http://aaa.bbb.ccc/v2")]
[XmlInclude(typeof(OutputHeaderSubclass))] // Artificial subtype to trigger handling of the `xsi:type` attribute.
[XmlInclude(typeof(OutputHeader))]
public class OutputHeader
{
[XmlElement(ElementName = "FAULT", Namespace = "")]
public Fault FaultSection { get; set; }
[XmlElement(ElementName = "CNL-OUT", Namespace = "")]
public string ClnOut { get; set; }
}
[XmlRoot(ElementName = "OUTPUT-HEADER-SUBCLASS", Namespace = "http://aaa.bbb.ccc/v2")]
public class OutputHeaderSubclass : OutputHeader
{
}
然后反序列化为 OutputHeader
可能会很好。不幸的是,事实并非如此。 XmlSerializer
为冗余属性抛出异常而不是处理它。相反,DataContractSerializer
没有,所以这就是要使用的。