C# parse soap response for elements and attribute values

Markus Freitag 3,786 Reputation points
2022-01-27T13:08:21.67+00:00

Hello,
I have a SOAP C#Desktop application.
This can return an error.
Is there a way to simply parse this return string?
If yes, how?

I need ErrorNumber, Message, faultcode, faultstring
What do I have to consider when reading out? Namespace and so on

Thank you.

Works not

XDocument doc = XDocument.Parse(xmlAnalyse);
                XNamespace ns = "http://schemas.xmlsoap.org/soap/envelope/";

                //Grab the reader
                var reader = xDoc.CreateReader();
                //Set the root
                var root = xDoc.Root;
                //Use the reader NameTable
                var namespaceManager = new XmlNamespaceManager(reader.NameTable);

                IEnumerable<XElement> responses = doc.Descendants(ns + "OracleError");
                foreach (XElement response in responses)
                {
                    string strResponseErrorNumber = (string)response.Element(ns + "ErrorNumber");
                    string strResponseMessage = (string)response.Element(ns + "Message");
                }


<soap:Envelope
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <soap:Fault>
            <faultcode>soap:Client</faultcode>
            <faultstring>Error processing input</faultstring>
            <detail>
                <OracleErrors
                    xmlns="http://xmlns.oracle.com/orawdsv/faults">
                    <OracleError>
                        <ErrorNumber>ORA-41821</ErrorNumber>
                        <Message>XML parsing failed</Message>
                    </OracleError>
                </OracleErrors>
            </detail>
        </soap:Fault>
    </soap:Body>
</soap:Envelope>
ASP.NET
ASP.NET
A set of technologies in the .NET Framework for building web applications and XML web services.
3,234 questions
Windows Server
Windows Server
A family of Microsoft server operating systems that support enterprise-level management, data storage, applications, and communications.
12,035 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,165 questions
{count} votes

Accepted answer
  1. Yitzhak Khabinsky 24,836 Reputation points
    2022-01-27T13:51:02.567+00:00

    HI @Markus Freitag ,

    Please try the following solution.

    c#

    void Main()  
    {  
    	XDocument xdoc = XDocument.Parse(@"<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>  
    		<soap:Body>  
    			<soap:Fault>  
    				<faultcode>soap:Client</faultcode>  
    				<faultstring>Error processing input</faultstring>  
    				<detail>  
    					<OracleErrors xmlns='http://xmlns.oracle.com/orawdsv/faults'>  
    						<OracleError>  
    							<ErrorNumber>ORA-41821</ErrorNumber>  
    							<Message>XML parsing failed</Message>  
    						</OracleError>  
    					</OracleErrors>  
    				</detail>  
    			</soap:Fault>  
    		</soap:Body>  
    	</soap:Envelope>");  
      
    	string faultcode = xdoc.Descendants("faultcode").FirstOrDefault()?.Value;  
    	string faultstring = xdoc.Descendants("faultstring").FirstOrDefault()?.Value;  
    	Console.WriteLine("faultcode='{0}', faultstring='{1}'", faultcode, faultstring);  
      
    	XNamespace ns = "http://xmlns.oracle.com/orawdsv/faults";  
    	IEnumerable<XElement> OracleError = xdoc.Descendants(ns + "OracleError");  
      
    	foreach (XElement xelem in OracleError)  
    	{  
    		string strResponseErrorNumber = (string)xelem.Element(ns + "ErrorNumber")?.Value;  
    		string strResponseMessage = (string)xelem.Element(ns + "Message")?.Value;  
    		Console.WriteLine("ErrorNumber='{0}', Message='{1}'", strResponseErrorNumber, strResponseMessage);  
    	}  
    }  
    

    Output

    faultcode='soap:Client', faultstring='Error processing input'  
    ErrorNumber='ORA-41821', Message='XML parsing failed'  
    

3 additional answers

Sort by: Most helpful
  1. Michael Taylor 47,461 Reputation points
    2022-01-27T15:50:45.517+00:00

    Please don't. Are you writing the TCP network calls to talk to your database? Are you hand building the web server hosting your site? If the answer is no then you see why hand parsing SOAP is always the wrong answer. It is complex, you aren't going to do it correctly and it'll be slow. .NET already supports SOAP out of the box. If you are mucking with XML or headers by hand you are doing it the hard way for no valid reason.

    Use Connected Services in VS, point it to your WSDL. It'll auto-generate all the code to handle the call and report errors as exceptions. Use the generated client to send the SOAP request and get the response. If something goes wrong you get FaultException back that has all the information you are trying to parse by hand. It literally takes a couple lines of code to make this call compared to your multi-line code trying to parse the XML.

       using (var client = new MyServiceClient())  
       {  
           try  
           {  
              client.MakeSoapCall();  
           } catch (FaultException e)  
           {  
              var code = e.Code;  
              var message = e.Message;  
              var reason = e.Reason;  
           };  
         
       };  
    
    1 person found this answer helpful.

  2. AgaveJoe 26,031 Reputation points
    2022-01-27T16:31:20.91+00:00

    I agree with cooldadtx, it's unusual to for a SOAP service to return a soap fault or response type that is not defined in the WSDL. The most likely scenario is you do not understand how the server works. Frankly, interacting with a SOAP service should take just a few minutes to get up and running.

    Anyway, if you want to parse the XML into a type yourself, simply copy the XML. In Visual Studio select Edit -> Paste Special -> Paste XML as classes. Then use the standard XML serializer to populate a C# type. Anyway, this is what the proxy class does automatically except only the response type is return (the result of a SOAP action) where as the example below deserializes the the entire SOAP envelope (the XML you shared). You'll need to create code that maps the SOAP actions to the possible response types which is what the WSDL does...

    https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer.deserialize?view=net-6.0

    using Newtonsoft.Json;  
    using System;  
    using System.Collections.Generic;  
    using System.Configuration;  
    using System.IO;  
    using System.Linq;  
    using System.Text;  
    using System.Threading.Tasks;  
    using System.Xml.Serialization;  
      
    namespace ConsoleApp1  
    {  
        class Program  
        {  
            static void Main(string[] args)  
            {  
                DeserializeObject("XMLFile1.xml");  
            }  
      
      
            private static void DeserializeObject(string filename)  
            {  
                // Create an instance of the XmlSerializer.  
                XmlSerializer serializer = new XmlSerializer(typeof(Envelope));  
      
                // Declare an object variable of the type to be deserialized.  
                Envelope e;  
      
                using (Stream reader = new FileStream(filename, FileMode.Open))  
                {  
                    // Call the Deserialize method to restore the object's state.  
                    e = (Envelope)serializer.Deserialize(reader);  
                }  
      
                // Write out the properties of the object.  
                Console.WriteLine(e.Body.GET_PCB_IDOutput.P_OUT.RESPONSE_SIE.TIMESTAMP);  
                Console.WriteLine(e.Body.GET_PCB_IDOutput.P_OUT.RESPONSE_SIE.PROCESSINGSTATUS.RETURNDESCRIPTION);  
            }  
        }  
      
      
        // NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.  
        /// <remarks/>  
        [System.SerializableAttribute()]  
        [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 bodyField;  
      
            /// <remarks/>  
            public EnvelopeBody Body  
            {  
                get  
                {  
                    return this.bodyField;  
                }  
                set  
                {  
                    this.bodyField = value;  
                }  
            }  
        }  
      
        /// <remarks/>  
        [System.SerializableAttribute()]  
        [System.ComponentModel.DesignerCategoryAttribute("code")]  
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]  
        public partial class EnvelopeBody  
        {  
      
            private GET_PCB_IDOutput gET_PCB_IDOutputField;  
      
            /// <remarks/>  
            [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://xmlns.oracle.com/orawsv/PDS/PS_PFWI")]  
            public GET_PCB_IDOutput GET_PCB_IDOutput  
            {  
                get  
                {  
                    return this.gET_PCB_IDOutputField;  
                }  
                set  
                {  
                    this.gET_PCB_IDOutputField = value;  
                }  
            }  
        }  
      
        /// <remarks/>  
        [System.SerializableAttribute()]  
        [System.ComponentModel.DesignerCategoryAttribute("code")]  
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://xmlns.oracle.com/orawsv/PDS/PS_PFWI")]  
        [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://xmlns.oracle.com/orawsv/PDS/PS_PFWI", IsNullable = false)]  
        public partial class GET_PCB_IDOutput  
        {  
      
            private GET_PCB_IDOutputP_OUT p_OUTField;  
      
            /// <remarks/>  
            public GET_PCB_IDOutputP_OUT P_OUT  
            {  
                get  
                {  
                    return this.p_OUTField;  
                }  
                set  
                {  
                    this.p_OUTField = value;  
                }  
            }  
        }  
      
        /// <remarks/>  
        [System.SerializableAttribute()]  
        [System.ComponentModel.DesignerCategoryAttribute("code")]  
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://xmlns.oracle.com/orawsv/PDS/PS_PFWI")]  
        public partial class GET_PCB_IDOutputP_OUT  
        {  
      
            private GET_PCB_IDOutputP_OUTRESPONSE_SIE rESPONSE_SIEField;  
      
            /// <remarks/>  
            public GET_PCB_IDOutputP_OUTRESPONSE_SIE RESPONSE_SIE  
            {  
                get  
                {  
                    return this.rESPONSE_SIEField;  
                }  
                set  
                {  
                    this.rESPONSE_SIEField = value;  
                }  
            }  
        }  
      
        /// <remarks/>  
        [System.SerializableAttribute()]  
        [System.ComponentModel.DesignerCategoryAttribute("code")]  
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://xmlns.oracle.com/orawsv/PDS/PS_PFWI")]  
        public partial class GET_PCB_IDOutputP_OUTRESPONSE_SIE  
        {  
      
            private string mESSAGEIDField;  
      
            private System.DateTime tIMESTAMPField;  
      
            private string iNTERFACEIDField;  
      
            private GET_PCB_IDOutputP_OUTRESPONSE_SIEPROCESSINGSTATUS pROCESSINGSTATUSField;  
      
            private object pROGField;  
      
            /// <remarks/>  
            public string MESSAGEID  
            {  
                get  
                {  
                    return this.mESSAGEIDField;  
                }  
                set  
                {  
                    this.mESSAGEIDField = value;  
                }  
            }  
      
            /// <remarks/>  
            public System.DateTime TIMESTAMP  
            {  
                get  
                {  
                    return this.tIMESTAMPField;  
                }  
                set  
                {  
                    this.tIMESTAMPField = value;  
                }  
            }  
      
            /// <remarks/>  
            public string INTERFACEID  
            {  
                get  
                {  
                    return this.iNTERFACEIDField;  
                }  
                set  
                {  
                    this.iNTERFACEIDField = value;  
                }  
            }  
      
            /// <remarks/>  
            public GET_PCB_IDOutputP_OUTRESPONSE_SIEPROCESSINGSTATUS PROCESSINGSTATUS  
            {  
                get  
                {  
                    return this.pROCESSINGSTATUSField;  
                }  
                set  
                {  
                    this.pROCESSINGSTATUSField = value;  
                }  
            }  
      
            /// <remarks/>  
            public object PROG  
            {  
                get  
                {  
                    return this.pROGField;  
                }  
                set  
                {  
                    this.pROGField = value;  
                }  
            }  
        }  
      
        /// <remarks/>  
        [System.SerializableAttribute()]  
        [System.ComponentModel.DesignerCategoryAttribute("code")]  
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://xmlns.oracle.com/orawsv/PDS/PS_PFWI")]  
        public partial class GET_PCB_IDOutputP_OUTRESPONSE_SIEPROCESSINGSTATUS  
        {  
      
            private string rETURNVALUEField;  
      
            private string rETURNCODEField;  
      
            private string rETURNDESCRIPTIONField;  
      
            /// <remarks/>  
            public string RETURNVALUE  
            {  
                get  
                {  
                    return this.rETURNVALUEField;  
                }  
                set  
                {  
                    this.rETURNVALUEField = value;  
                }  
            }  
      
            /// <remarks/>  
            public string RETURNCODE  
            {  
                get  
                {  
                    return this.rETURNCODEField;  
                }  
                set  
                {  
                    this.rETURNCODEField = value;  
                }  
            }  
      
            /// <remarks/>  
            public string RETURNDESCRIPTION  
            {  
                get  
                {  
                    return this.rETURNDESCRIPTIONField;  
                }  
                set  
                {  
                    this.rETURNDESCRIPTIONField = value;  
                }  
            }  
        }  
      
      
    }  
      
    

    Results

    1/27/2022 10:07:19 AM  
    Receiver not running (WS Siemens App)  
    
    1 person found this answer helpful.

  3. AgaveJoe 26,031 Reputation points
    2022-01-27T20:55:47.703+00:00

    I disagree the XDocument example is a simpler solution. I feel strong types are a more maintainable approach than strings. Above all I recommend following standard SOAP service patterns in .NET. It does not make a lot of sense to manually parse a SOAP response when the framework has well-tested libraries that handle SOAP.

    Anyway, based on the previous example...

    static void Main(string[] args)
    {
        XDocument xdoc = XDocument.Parse(@"<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
        <soap:Body>
            <GET_PCB_IDOutput xmlns=""http://xmlns.oracle.com/orawsv/PDS/PS_PFWI"">
                <P_OUT>
                    <RESPONSE_SIE>
                        <MESSAGEID>f7de543c6-ad46-4230-831f-9e7777cf9e1b</MESSAGEID>
                        <TIMESTAMP>2022-01-27T16:07:19.387+01:00</TIMESTAMP>
                        <INTERFACEID>IF0FFF001</INTERFACEID>
                        <PROCESSINGSTATUS>
                            <RETURNVALUE>REJECTED</RETURNVALUE>
                            <RETURNCODE>PWS-2777</RETURNCODE>
                            <RETURNDESCRIPTION>Receiver not running (WS Siemens App)</RETURNDESCRIPTION>
                        </PROCESSINGSTATUS>
                        <PROG/>
                    </RESPONSE_SIE>
                </P_OUT>
            </GET_PCB_IDOutput>
        </soap:Body>
    </soap:Envelope>");
    
    
        XNamespace ns = "http://xmlns.oracle.com/orawsv/PDS/PS_PFWI";
        string ts = xdoc.Root.Descendants(ns + "TIMESTAMP").FirstOrDefault().Value;
        string desc = xdoc.Root.Descendants(ns + "RETURNDESCRIPTION").FirstOrDefault().Value;
        Console.WriteLine($"{ts}\r\n{desc}");
    }
    

    Results

    2022-01-27T16:07:19.387+01:00
    Receiver not running (WS Siemens App)
    
    0 comments No comments