2013-03-14 3 views
14

J'ai un service Web qui renvoie les données suivantes:XML désérialisation avec DataContractSerializer

<?xml version=""1.0"" encoding=""UTF-8""?> 
<RESPONSE> 
    <KEY>12345</KEY> 
    <PROPERTY> 
     <PROPERTY_ADDRESS> 
      <STREET_NUM>25</STREET_NUM> 
      <STREET_ADDRESS>ELM ST</STREET_ADDRESS> 
      <STREET_PREFIX/> 
      <STREET_NAME>ELM</STREET_NAME> 
      <STREET_TYPE>ST</STREET_TYPE> 
      <STREET_SUFFIX/> 
     </PROPERTY_ADDRESS> 
    </PROPERTY> 
</RESPONSE> 

J'ai une structure de classe pour correspondre:

[DataContract(Name="RESPONSE", Namespace="")] 
public class Response 
{ 
    [DataMember(Name="KEY")] 
    public string Key { get; set; } 

    [DataMember(Name = "PROPERTY")] 
    public Property Property { get; set; } 
} 

[DataContract(Name="PROPERTY", Namespace="")] 
public class Property 
{ 
    [DataMember(Name="PROPERTY_ADDRESS")] 
    public PropertyAddress Address { get; set; } 
} 


[DataContract(Name="PROPERTY_ADDRESS", Namespace="")] 
public class PropertyAddress 
{ 
    [DataMember(Name="STREET_NUM")] 
    public string StreetNumber { get; set; } 

    [DataMember(Name = "STREET_ADDRESS")] 
    public string StreetAddress { get; set; } 

    [DataMember(Name = "STREET_PREFIX")] 
    public string StreetPrefix { get; set; } 

    [DataMember(Name = "STREET_NAME")] 
    public string StreetName { get; set; } 

    [DataMember(Name = "STREET_TYPE")] 
    public string StreetType { get; set; } 

    [DataMember(Name = "STREET_SUFFIX")] 
    public string StreetSuffix { get; set; } 
} 

Mon code désérialisation ressemble à ceci:

[Test] 
public void TestMapping() 
{ 
    var serializer = new DataContractSerializer(typeof(Response)); 

    Response response = null; 

    using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(XmlData))) 
    { 
     response = (Response)serializer.ReadObject(ms); 
    } 

    //This works 
    Assert.AreEqual("12345", response.Key); 

    //This works 
    Assert.AreEqual("25", response.Property.Address.StreetNumber); 

    //This FAILS. StreetAddress is null 
    Assert.AreEqual("ELM ST", response.Property.Address.StreetAddress); 
} 

Pour la vie de moi, je ne peux pas comprendre pourquoi StreetAddress échoue. Ça doit être quelque chose de simple qui me manque.

+0

quelle valeur en êtes-vous dans les biens exactement, pouvez-vous faire un testcontext.writeline sur chaque propriété pour voir la valeur. –

+0

response.Property.Address.StreetNumber == "25" response.Property.Address.StreetAddress == null – Micah

+0

Modifiez StreetAddress à int pour voir s'il s'agit du nom ou du type de la propriété qui a échoué. –

Répondre

23

DataContractSerializer s'attend à ce que les éléments soient in alphabetical order. Vous devez ajouter Order à vos données membres pour que cela fonctionne correctement.

[DataContract(Name = "PROPERTY_ADDRESS", Namespace = "")] 
public class PropertyAddress 
{ 
    [DataMember(Name = "STREET_NUM", Order=0)] 
    public string StreetNumber { get; set; } 

    [DataMember(Name = "STREET_ADDRESS", Order=1)] 
    public string StreetAddress { get; set; } 

    [DataMember(Name = "STREET_PREFIX", Order=2)] 
    public string StreetPrefix { get; set; } 

    [DataMember(Name = "STREET_NAME", Order=3)] 
    public string StreetName { get; set; } 

    [DataMember(Name = "STREET_TYPE", Order=4)] 
    public string StreetType { get; set; } 

    [DataMember(Name = "STREET_SUFFIX",Order=5)] 
    public string StreetSuffix { get; set; } 
} 
+0

@Micah: C'est pour des raisons de performances. En attendant les balises dans un certain ordre, DataContractSerializer peut gagner du temps en faisant correspondre les balises du contrat avec les balises de message. Et il doit y avoir un ordre par défaut si aucun n'est spécifié explicitement. – Vizu

+19

Je pense que tous les gains de 'performance' sont plus que compensés par la quantité de temps de développement gaspillé à essayer de trouver, déboguer, et réparer cette exigence idiote. –

+0

Alors ... comment désactiver ce comportement? – BrainSlugs83

6

Vous avez augmenter votre contrat de données avec l'ordre des éléments parce DataContractSerializer attend les éléments triés par ordre alphabétique par défaut. Ce qui n'est pas le cas avec votre XML.

Voici le code:

[DataContract(Name = "PROPERTY_ADDRESS", Namespace = "")] 
public class PropertyAddress 
{ 
    [DataMember(Name = "STREET_NUM", Order=1)] 
    public string StreetNumber { get; set; } 

    [DataMember(Name = "STREET_ADDRESS", Order=2)] 
    public string StreetAddress { get; set; } 

    [DataMember(Name = "STREET_PREFIX", Order=3)] 
    public string StreetPrefix { get; set; } 

    [DataMember(Name = "STREET_NAME", Order=4)] 
    public string StreetName { get; set; } 

    [DataMember(Name = "STREET_TYPE", Order=5)] 
    public string StreetType { get; set; } 

    [DataMember(Name = "STREET_SUFFIX", Order=6)] 
    public string StreetSuffix { get; set; } 
} 
Questions connexes