2013-08-21 72 views
2

我有一個RESTful WCF服務,我試圖發送一個任務列表。我發現在其他問題上,你必須封裝列表,我已經完成了,序列化看起來好像很順利。反序列化對象列表產生空列表

是來自序列化列表中的XML看起來像:

<?xml version="1.0" encoding="utf-8"?> 
<MobileRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <TaskRequests xmlns="MyNameSpace"> 
    <MobileTask> 
     <TaskArgs xsi:type="GetUser"> 
     <Password>test</Password> 
     <UserName>t</UserName> 
     </TaskArgs> 
     <TaskID>1</TaskID> 
     <TaskType>GetUser</TaskType> 
    </MobileTask> 
    <MobileTask> 
     <TaskArgs xsi:type="GetUser"> 
     <Password>test</Password> 
     <UserName>t2</UserName> 
     </TaskArgs> 
     <TaskID>2</TaskID> 
     <TaskType>GetUser</TaskType> 
    </MobileTask> 
    </TaskRequests> 
</MobileRequest> 

所以MobileRequest類有一個屬性是MobileTask對象的列表。對於MobileRequest類的代碼是非常簡單的,看起來像:

<Serializable(), DataContract(Name:="MobileRequest", [Namespace]:="MyNameSpace")> _ 
Public Class MobileRequest 
    <XmlArray()> <DataMember(Name:="TaskRequests")> _ 
    Public TaskRequests As List(Of MobileTask) = New List(Of MobileTask) 

    Public Sub New() 
     Me.TaskRequests = New List(Of MobileTask) 
    End Sub 
End Class 

的MobileTask類的樣子:

<Serializable(), DataContract(Name:="MobileTask", [Namespace]:="MyNamespace"), _ 
KnownType(GetType(Obj.GetUser)), XmlInclude(GetType(Obj.GetUser))> _ 
Public Class MobileTask 
    Public Enum TypesOfTasks As Integer 
     Unknown = 0 
     GetUser = 1 
    End Enum 

    <DataMember(Name:="TaskID")> _ 
    Public TaskID As Integer 
    <DataMember(Name:="TaskType")> _ 
    Public TaskType As TypesOfTasks 
    <DataMember(Name:="TaskArgs")> _ 
    Public TaskArgs As Object 
End Class 

類型TaskArgs的視任務類型而變化。我爲TaskArgs可能包含的每種可能類型都包含了一個XMLInclude和KnownType標記。 (這可能是矯枉過正,但我​​做到了,當事情與序列不工作,只是沒有試圖把它清理乾淨又)

的代碼,我用我的測試應用程序試圖反序列化XML是:

Using logg As New System.IO.MemoryStream() 
    Using sw As New System.IO.StreamWriter(logg) 
     sw.Write(txtSource.Text) 
     sw.Flush() 
     If logg.Length > 0 Then 
      Using reader As New System.IO.StreamReader(logg) 
       logg.Position = 0 
       Dim ser As New System.Xml.Serialization.XmlSerializer(GetType(SMS_VendorObj.MobileRequest)) 
       Dim results = ser.Deserialize(logg) 
      End Using 
     End If 
    End Using 
End Using 

這是從一個簡單的WinForm的設置,讓我在XML粘貼所以txtSource僅僅是我把XML我從串行化爲得到一個文本框。

在運行測試程序我可以通過以上反序列化碼和Dim results = ser.Deserialize(logg)results步驟之後是正確的類型,但MobileTask列表不包含任何項目。

我是否在類文件中丟失了某些東西,或者我試圖反序列化列表的方式有問題嗎?

如果我錯過了重要的代碼,請讓我知道,我會更新所需的任何其他內容。我還編輯了多餘的部分,所以我可能會在沒有意識到的情況下削減太多。

編輯:GetUser類:

<Serializable(), DataContract([Namespace]:="MyNamespace")> _ 
Public Class GetUser 

    <DataMember(Name:="UserName")> _ 
    Public UserName As String 
    <DataMember(Name:="Password")> _ 
    Public Password As String 
End Class 

編輯#2: 處理的錯誤,解串器都不可能扔我發現,反序列化過程中拋出UnknownNode異常之後進行後一個UnknownElement異常在第21行,位置3.細節說預期的元素是「:TaskRequests」。

+0

對不起,沒注意到你已經有了XmlInclude。你能否顯示類型Obj.GetUser的定義? – BartoszKP

+0

@BartoszKP請參考編輯。 –

+0

您是否嘗試過將'XmlInclude'屬性('KnownType'與此處引用的'DataContractSerializer'無關)轉移到屬性TaskArgs? – BartoszKP

回答

3

好的,我已經在C#中重新實現了你的解決方案,其中最重要的是你沒有爲MobileRequest類中的TaskRequests提供命名空間。

總結:

1)您對DataContractSerializerXmlSerializer這使得該代碼難以管理的混合屬性中,我只用XmlSerializer相關的屬性。

2)您提供不能是序列化你提出的類的結果的XML。它包含TaskReqests字段上的「MyNameSpace」,而在您的代碼中沒有XmlSerializer的名稱空間(僅適用於DataContractSerializer,這與此處不相關)。

3)你的代碼的最小修復,使你給反序列化 正確 XML(見下面編輯)是:

[Serializable] 
public class MobileRequest 
{ 
    [XmlArray(Namespace="MyNameSpace")] //note the namespace 
    public List<MobileTask> TaskRequests = new List<MobileTask>(); 

    public MobileRequest() 
    { 
     TaskRequests = new List<MobileTask>(); 
    } 
} 

(我也刪除了清晰DataContractSerializer屬性)。 這是在C#中,但我希望你可以很容易地發現差異 - 給Namespace參數XmlArray屬性。

可能有用的參考資料:

http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer%28v=vs.90%29.aspx

http://www.codeproject.com/Articles/14064/Using-the-XmlSerializer-Attributes

編輯:

事實證明,XmlSerializer的不能反序列化是什麼連載本身!使用具有所描述的修復以上定義的類下面的代碼後:

XmlSerializer s = new XmlSerializer(typeof(MobileRequest)); 

MobileRequest mr = new MobileRequest(); 
mr.TaskRequests.Add(new MobileTask() { TaskID = 1, TaskType = MobileTask.TypesOfTasks.GetUser, TaskArgs = new Obj.GetUser() { Password = "test", UserName = "t" } }); 
mr.TaskRequests.Add(new MobileTask() { TaskID = 2, TaskType = MobileTask.TypesOfTasks.GetUser, TaskArgs = new Obj.GetUser() { Password = "test", UserName = "t2" } }); 

using (StreamWriter sw = new StreamWriter("test.txt")) 
{ 
    s.Serialize(sw, mr); 
} 

StreamReader sr = new StreamReader("test.txt"); 
XmlReader xmlReader = XmlReader.Create(sr); 
XmlDeserializationEvents xde = new XmlDeserializationEvents(); 
xde.OnUnknownElement = new XmlElementEventHandler((o, e) => 
{ 
    Console.WriteLine("Unknown element:" + e.Element.Name); 
}); 
xde.OnUnknownNode = new XmlNodeEventHandler((o, e) => 
    { 
    Console.WriteLine("Unknown node:" + e.Name); 
    }); 
var r = s.Deserialize(xmlReader, xde); 
Console.ReadKey(); 

XmlNodes出現,而不是TaskArgs!刪除所有名稱空間定義和引用可解決問題。我已經閱讀了關於XmlSerializer的許多問題,尤其是命名空間方面的問題,所以如果可以的話,您可能需要按照本主題中的建議使用DataContractSerializerNetDataContractSerializerWhy is XmlSerializer's Deserialize() spitting out a child object which is a XmlNode[]?

+0

我用另一個想法更新了答案。 – BartoszKP

+0

環境一直說「屬性'XmlIncluedAttribute'不能應用於'TaskArgs',因爲該屬性在該聲明中無效」。但是當我瀏覽鏈接的文檔時,我注意到你可以處理未知元素/節點/屬性事件,以獲得更多關於反序列化失敗原因的信息。我會盡力獲得更多信息,並用我發現的內容更新問題。 –

+0

我通過文檔閱讀了更多內容,並將該類上的XMLInclude標記切換爲屬性上的XMLElement標記。我還能夠找到更多關於實際錯誤的信息,並更新了問題。 –