2017-03-15 119 views
2

由於xsi:type =「p:OUTPUT-HEADER」屬性,我正在試圖反序列化與WCF SOAP服務FAULT詳細信息部分相對應的這段XML代碼塊:XmlSerializer和xsi:反序列化

<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)); 

其中t他錯誤調用反序列化方法時,我得到:

「指定的類型無法識別:命名 = 'OUTPUT-標頭',命名空間= 'http://aaa.bbb.ccc/v2',在< OUTPUT-HEADER 的xmlns = 'http://aaa.bbb.ccc/v2' >「。

是否可以修飾類以正確反序列化此XML? 任何想法非常感謝,謝謝!

+0

WCF將序列化和反序列化通過導線自動發送的內容。是否有一個特定的原因需要手動完成? –

+0

我明白'auto'的方法應該是使用FaultException.GetDetail ,但沒有OutputHeader類已生成,因爲wsdl不包含任何與之相關的信息。所以我的下一步是獲取FaultException.GetReaderAtDetailContents()流並嘗試對其進行反序列化。或者我在這裏錯過了什麼?謝謝! – mack

回答

0

而不是XmlSerializer,似乎您必須使用DataContractSerializer來反序列化此XML。該序列化程序是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]切換回數據合同序列化,並且應該全部設置。有關切換見Using the XmlSerializer Class

細節(注還需要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> 

有鹼型OUTPUT-HEADER在命名空間http://aaa.bbb.ccc/v2和亞型OUTPUT-HEADER在命名空間http://aaa.bbb.ccc/v2 - 即類型和子類型的信息是相同的,所以xsi:type屬性是多餘的。

但是,如果它是多餘的,它應該是無害的,對吧?

[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。不幸的是,事實並非如此。XmlSerializer爲冗餘屬性引發異常而不是處理它。相反,DataContractSerializer沒有,所以這是一個使用。

+0

令人印象深刻,很好解釋和記錄的答案。我使用XmlSerializer,因爲我認爲DataContractSerializar不能處理層次中的不同名稱空間,但是現在我看到我誤解了XML。非常感謝dbc! – mack

相關問題