Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the detail of an untyped FaultException?

Tags:

c#

soap

I'm calling a SOAP web service from .NET 4.5 using C#, and I can't understand how to catch the detail of an untyped FaultException.

If the web service experiences an error, I get a message like this one:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
         <faultcode>GSX.SYS.003</faultcode>
         <faultstring>Multiple error messages exist. Please check the detail section.</faultstring>
         <detail>
            <operationId>HqrCoRMbtKczWFH2WMuFJGe</operationId>
            <errors>
               <error>
                  <code>ENT.UPL.005</code>
                  <message>User ID is required for authentication.</message>
               </error>
               <error>
                  <code>ENT.UPL.005</code>
                  <message>Password is required for authentication.</message>
               </error>
               <error>
                  <code>ENT.UPL.005</code>
                  <message>Sold-To is required for authentication.</message>
               </error>
            </errors>
         </detail>
      </S:Fault>
   </S:Body>
</S:Envelope>

To catch the error, I wrap the call in a try/catch block and catch the FaultException:

try
{
    // Do something.
}
catch (FaultException faultException)
{
    var messageFault = faultException.CreateMessageFault();
    // ???
    throw;
}

The problem lies in the // ??? line: how can I access the detail of the FaultException, given that I can't use messageFault.GetDetail<T>() because the detail is untyped?

For the code and the reason I don't have a problem, I get them with messageFault.Code.Name and messageFault.Reason.Translations.Single().Text.

What I've been able to concoct is this:

var stringWriter = new StringWriter();
var xmlTextWriter = new XmlTextWriter(stringWriter);
var messageFault = faultException.CreateMessageFault();
messageFault.WriteTo(xmlTextWriter, EnvelopeVersion.Soap12);
var stringValue = Convert.ToString(stringWriter);
var nameTable = new NameTable();
var xmlNamespaceManager = new XmlNamespaceManager(nameTable);
xmlNamespaceManager.AddNamespace("soap", "http://www.w3.org/2003/05/soap-envelope");
var xmlDocument = XDocument.Parse(stringValue);
var operationId =
    xmlDocument
    .XPathSelectElement("/soap:Fault/soap:Detail/operationId", xmlNamespaceManager)
    .Value;
var errors =
    xmlDocument
    .XPathSelectElements("/soap:Fault/soap:Detail/errors/error", xmlNamespaceManager)
    .Select(element => new
        {
            Code = element.XPathSelectElement("code").Value,
            Message = element.XPathSelectElement("message").Value
        })
    .ToArray();

But null reference and encoding issues aside, it's a monster.

There must be a saner way to get the details.

like image 220
Albireo Avatar asked Nov 02 '22 18:11

Albireo


1 Answers

You can read the detail as an XML type, eg. XElement or XmlElement and process it using XPath, Linq to XML or just treat it as string.

In a similar situation I use the following code to get at the contents of an admittedly simple details element:

var detail = fault.GetDetail<XElement>();
return detail.Value;
like image 129
Panagiotis Kanavos Avatar answered Nov 15 '22 06:11

Panagiotis Kanavos