反序列化SOAP消息的细节

时间:2012-10-12 08:54:47

标签: c# soap xml-serialization windows-8 .net-4.5

我正在开发Windows应用商店。

我有以下手动创建的Fault类:

[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属性,但我总是以SoapFault中的Detail属性为NULL。当我将类型更改为对象时,我至少得到一个包含数据的XmlNode集。

我必须在此代码中更改什么才能在序列化上实例化正确的类?

请注意:我不幸被迫手动创建电话,不能使用自动生成的代码。

1 个答案:

答案 0 :(得分:6)

受到How to Deserialize XML document的极大启发,我认为这应该可以解决问题。

我按如下方式生成了这个类:

  1. 将Xml服务器回复保存到磁盘(c:\ temp \ reply.xml)
  2. xsd c:\ temp \ reply.xml / o:“c:\ temp”
  3. xsd c:\ temp \ reply.xsd reply_app1.xsd / classes / o:“c:\ temp”
  4. 将reply_app1.cs添加到您的项目中。
  5. 这导致:

    //------------------------------------------------------------------------------
    // <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以适应。