繁体   English   中英

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 ',位于<OUTPUT-HEADER xmlns =' http://aaa.bbb.ccc/ v2 '>。”

是否可以装饰类以正确反序列化此XML? 任何想法都将不胜感激,谢谢!

似乎您必须使用DataContractSerializer而不是XmlSerializer来反序列化此XML。 该序列化程序是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] ,切换回数据合同序列化,您应该已经准备就绪。 有关切换的详细信息,请参见使用XmlSerializer类。

(还要注意, Fault的属性需要放置在正确的名称空间中。)

为什么这样做

"xsi:type"属性是w3c标准属性,它允许元素显式声明其类型。 XmlSerializerDataContractSerializer都在序列化多态类型时使用此属性来传达实际的类型信息。 但是,以下元素:

<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 http://aaa.bbb.ccc/v2即类型和子类型信息相同,因此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则没有,所以这是要使用的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM