Deserializing a SOAP Message Detail

I am working on a Windows Store app.

I have the following manually created Fault class:

[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; } } 

This is the server response I am reading:

 <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> 

The way I'm trying to read this is as follows:

 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); } } 

I tried to add namespaces by changing the XmlElement attributes, but always get the Detail property in SoapFault equal to NULL. When I change the type to an object, I at least get an XmlNode set that contains the data.

What should I change in this code to get the correct instance of the class during serialization?

Please note: I unfortunately have to create calls manually and cannot use the automatically generated code.

+4
source share
1 answer

Strongly inspired How to deserialize an XML document , I think this should do the trick.

I generated the class as follows:

  • Save the Xml server response to disk (c: \ temp \ reply.xml)
  • xsd c: \ temp \ reply.xml / o: "c: \ temp"
  • xsd c: \ temp \ reply.xsd reply_app1.xsd / classes / o: "c: \ temp"
  • Add reply_app1.cs to your project.

The result is:

 //------------------------------------------------------------------------------ // <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; } } } 

Yes, it is generated automatically, but I decided that it would be the easiest way to create a class that you could deserialize. What you can do as follows:

 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)); 

What took the Detail property correctly. In your case, you need to use the XmlReader , as you did before, instead of my new StringReader(document.OuterXml) , and wrap it in a use block, etc.

Keep in mind that some property names of the deserialized object will not exactly match what you had in your SoapFault class (now it is called Envelope , for example), and some of the properties are expressed as arrays, not separate objects, but you, probably could configure Xsd if necessary.

+6
source

Source: https://habr.com/ru/post/1439334/


All Articles