2012-10-12 3 views
4

Я работаю над приложением Windows Store.Deserializing detail сообщения SOAP

У меня есть следующий создан вручную Класс ошибки:

[XmlRoot(Namespace = "http://schemas.xmlsoap.org/soap/envelope/", ElementName = "Fault")] 
public partial class SoapFault 
{ 
    [XmlElement(Form = XmlSchemaForm.Unqualified, ElementName = "faultcode")] 
    public String FaultCode { get; set; } 

    [XmlElement(Form = XmlSchemaForm.Unqualified, ElementName = "faultstring")] 
    public String FaultDescription { get; set; } 

    [XmlElement(Form = XmlSchemaForm.Unqualified, ElementName = "detail")] 
    public InnerException[] Detail { get; set; } 
} 

    [XmlType(Namespace = "http://my.namespace.com", TypeName = "InnerException")] 
    public partial class InnerException 
    { 
     [XmlElement(Form = XmlSchemaForm.Unqualified, ElementName = "message")] 
     public String Message { get; set; } 
    } 

Это ответ сервера я пытаюсь читать:

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><env:Fault><faultcode>env:Server</faultcode><faultstring>internal error</faultstring><detail><ns2:InnerException xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://ns1.my.namespace.com" xmlns:ns2="http://my.namespace.com" xmlns:ns3="http://ns3.my.namespace.com"><message>internal error</message></ns2:InnerException ></detail></env:Fault></env:Body></env:Envelope> 

так, как я пытаюсь прочитать это, как следует:

using (XmlReader reader = XmlReader.Create(await response.Content.ReadAsStreamAsync())) 
{ 
    string SoapNamespace = "http://schemas.xmlsoap.org/soap/envelope/"; 
    try 
    { 
     var serializer = new XmlSerializer(typeof(SoapFault)); 

     reader.ReadStartElement("Envelope", SoapNamespace); 
     reader.ReadStartElement("Body", SoapNamespace); 

     var fault = serializer.Deserialize(reader) as SoapFault; 

     reader.ReadEndElement(); 
     reader.ReadEndElement(); 
    } 
    catch(Exception ex) 
    { 
     throw new Exception("Exception was thrown:" + ex.Message); 
    } 
} 

Я попытался добавить пространства имен, изменив атрибуты XmlElement, но я всегда заканчиваю а свойство Detail в SoapFault - NULL. Когда я меняю тип на объект, я, по крайней мере, получаю набор XmlNode, который содержит данные.

Что я должен изменить в этом коде, чтобы получить правильный экземпляр класса при сериализации?

Обратите внимание: я к несчастью вынужден создавать вызовы вручную и не могу использовать автоматически сгенерированный код.

ответ

6

Сильно вдохновленный How to Deserialize XML document, я думаю, что это должно сделать трюк.

Я создал класс следующим образом:

  1. Сохранить Xml ответа сервера на диск (C: \ Temp \ reply.xml)
  2. XSD C: \ Temp \ reply.xml/о:» c: \ temp "
  3. xsd c: \ temp \ reply.xsd reply_app1.xsd/classes/o:" c: \ temp "
  4. Добавьте reply_app1.cs в свой проект.

В результате:

//------------------------------------------------------------------------------ 
// <auto-generated> 
//  This code was generated by a tool. 
//  Runtime Version:4.0.30319.269 
// 
//  Changes to this file may cause incorrect behavior and will be lost if 
//  the code is regenerated. 
// </auto-generated> 
//------------------------------------------------------------------------------ 

using System.Xml.Serialization; 

// 
// This source code was auto-generated by xsd, Version=4.0.30319.1. 
// 

/// <remarks/> 
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] 
[System.SerializableAttribute()] 
[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.ComponentModel.DesignerCategoryAttribute("code")] 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/soap/envelope/")] 
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://schemas.xmlsoap.org/soap/envelope/", IsNullable=false)] 
public partial class Envelope { 

    private EnvelopeBody[] itemsField; 

    /// <remarks/> 
    [System.Xml.Serialization.XmlElementAttribute("Body")] 
    public EnvelopeBody[] Items { 
     get { 
      return this.itemsField; 
     } 
     set { 
      this.itemsField = value; 
     } 
    } 
} 

/// <remarks/> 
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] 
[System.SerializableAttribute()] 
[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.ComponentModel.DesignerCategoryAttribute("code")] 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/soap/envelope/")] 
public partial class EnvelopeBody { 

    private EnvelopeBodyFault[] faultField; 

    /// <remarks/> 
    [System.Xml.Serialization.XmlElementAttribute("Fault")] 
    public EnvelopeBodyFault[] Fault { 
     get { 
      return this.faultField; 
     } 
     set { 
      this.faultField = value; 
     } 
    } 
} 

/// <remarks/> 
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] 
[System.SerializableAttribute()] 
[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.ComponentModel.DesignerCategoryAttribute("code")] 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/soap/envelope/")] 
public partial class EnvelopeBodyFault { 

    private string faultcodeField; 

    private string faultstringField; 

    private EnvelopeBodyFaultDetail detailField; 

    /// <remarks/> 
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] 
    public string faultcode { 
     get { 
      return this.faultcodeField; 
     } 
     set { 
      this.faultcodeField = value; 
     } 
    } 

    /// <remarks/> 
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] 
    public string faultstring { 
     get { 
      return this.faultstringField; 
     } 
     set { 
      this.faultstringField = value; 
     } 
    } 

    /// <remarks/> 
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] 
    public EnvelopeBodyFaultDetail detail { 
     get { 
      return this.detailField; 
     } 
     set { 
      this.detailField = value; 
     } 
    } 
} 

/// <remarks/> 
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] 
[System.SerializableAttribute()] 
[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.ComponentModel.DesignerCategoryAttribute("code")] 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/soap/envelope/")] 
public partial class EnvelopeBodyFaultDetail { 

    private InnerException innerExceptionField; 

    /// <remarks/> 
    [System.Xml.Serialization.XmlElementAttribute(Namespace="http://my.namespace.com")] 
    public InnerException InnerException { 
     get { 
      return this.innerExceptionField; 
     } 
     set { 
      this.innerExceptionField = value; 
     } 
    } 
} 

/// <remarks/> 
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] 
[System.SerializableAttribute()] 
[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.ComponentModel.DesignerCategoryAttribute("code")] 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://my.namespace.com")] 
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://my.namespace.com", IsNullable=false)] 
public partial class InnerException { 

    private string messageField; 

    /// <remarks/> 
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] 
    public string message { 
     get { 
      return this.messageField; 
     } 
     set { 
      this.messageField = value; 
     } 
    } 
} 

Да, он автоматически генерируется, но я решил, что было бы самым простым способом, чтобы создать класс, который был бы в состоянии десериализации. Что вы можете сделать так:

XmlDocument document = new XmlDocument(); 
document.Load(Server.MapPath("~/Data/reply.xml")); 

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Envelope)); 
Envelope envelope = (Envelope)serializer.Deserialize(new StringReader(document.OuterXml)); 

Что правильно подобрал Detail собственности. В вашем случае вам нужно будет использовать XmlReader, как вы делали раньше вместо моего new StringReader(document.OuterXml), и завернуть его в использовании блока и т.д.

Имейте в виду, что некоторые из имен свойств десериализованное объекта не будет точно совпадают с тем, что у вас было в вашем классе SoapFault (теперь он называется Envelope), а некоторые свойства выражаются как массивы, а не отдельные объекты, но вы, вероятно, могли бы настроить Xsd в случае необходимости.

+1

для шага № 3 выше, если шаг № 2 сгенерировал более 2 файлов, вам может потребоваться перечислить их все как аргументы xsd, т.е. ** xsd ** * reply.xsd * * reply_app1.xsd * * reply_app2.xsd * ... и т. д. – mungflesh

+0

Вы спасаете жизнь – Yiping

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