2013-08-21 5 views
2

У меня есть служба RESTful WCF, к которой я пытаюсь отправить список задач. Я нашел по другим вопросам, что вам нужно инкапсулировать список, и я это сделал, и сериализация выглядит так, как будто все идет хорошо.Deserializing Список объектов дает пустой список

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 изменяется в зависимости от TaskType. Я включил теги XMLInclude и KnownType для каждого возможного типа, которым может быть TaskArgs. (это может быть излишним, но я сделал это, когда что-то с сериализацией не работало и просто еще не пыталось его очистить)

Код, который я использую в своем приложении-тесте, чтобы попытаться десериализовать 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 список не содержит каких-либо предметов.

Я что-то пропустил в файлах классов или что-то не так с тем, как я пытаюсь десериализовать список?

Если я пропустил важный код, пожалуйста, дайте мне знать, и я обновлю все, что еще нужно. Я также отредактировал избыточные части, поэтому я, возможно, слишком много срезал, не понимая этого.

Edit: GetUser класс:

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

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

Edit # 2: После обработки ошибок, что десериализатор может возможно бросить я обнаружил, что процесс десериализации бросает UnknownNode исключение с последующим исключение UnknownElement в строке 21, позиция 3. Подробности говорят, что ожидаемым элементом является «: TaskRequests».

+0

Извините, не заметил, что у вас уже есть XmlInclude. Не могли бы вы показать определение типа Obj.GetUser? – BartoszKP

+0

@BartoszKP, пожалуйста, обратитесь к редактированию. –

+0

Вы пытались переместить атрибут 'XmlInclude' (значение' KnownType' здесь не имеет значения, поскольку оно относится к 'DataContractSerializer') к свойству' TaskArgs'? – BartoszKP

ответ

3

Хорошо, я пересмотрел ваше решение на C#, и в чем разница, так это то, что вы не предоставили пространство имен для TaskRequests в классе MobileRequest.

Резюмируя:

1) Вы смешиваете атрибуты для DataContractSerializerXmlSerializer и что делает этот код трудно управлять, я использовал только XmlSerializer связанные атрибуты.

2) XML, который вы предоставили , не может быть результатом сериализации классов, которые вы представили. Он содержит «MyNameSpace» в поле TaskReqests, тогда как в вашем коде нет пространств имен для 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

EDIT:

Как выясняется, 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, особенно это касается проблем с пространствами имен, поэтому, если вы можете, вы, вероятно, захотите использовать DataContractSerializer или NetDataContractSerializer, как предложено в этой теме: Why is XmlSerializer's Deserialize() spitting out a child object which is a XmlNode[]?.

+0

Я обновил ответ с другой идеей. – BartoszKP

+0

Окружающая среда говорит: «Атрибут« XmlIncluedAttribute »не может применяться к« TaskArgs », потому что атрибут недействителен в этом объявлении». Но пока я пробирался через связанную вами документацию, я заметил, что вы можете обрабатывать события unkown element/node/attribute, чтобы получить дополнительную информацию о том, почему неудача десериализации не удалась. Я постараюсь получить дополнительную информацию и обновить вопрос тем, что я нахожу. –

+0

Я прочитал документацию а еще и переключил теги XMLInclude в классе на теги XMLElement в свойстве. Я также смог найти дополнительную информацию о фактической ошибке и обновил вопрос. –

Смежные вопросы