Extracting detail from a WCF FaultException response
Asked Answered
C

5

15

I am successfully working with a third party soap service. I have added a service reference to a soap web service which has auto generated the classes.

When an error occurs it returns a soap response like this:

<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Body>
      <SOAP-ENV:Fault>
         <faultcode>SOAP-ENV:Client</faultcode>
         <faultstring xsi:type="xsd:string">Error while reading parameters of method 'Demo'</faultstring>
         <detail xsi:type="xsd:string">Invalid login or password. Connection denied.</detail>
      </SOAP-ENV:Fault>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

I can catch the error but not extract the detail. I have tried the following code:

catch (FaultException ex)
{
    MessageFault msgFault = ex.CreateMessageFault();
    var elm = msgFault.GetDetail<string>();
    //throw Detail
}

However it Errors with the following as detail node is not an object:

Expecting element 'string' from namespace 'http://schemas.datacontract.org/2004/07/MyDemoNamespace'.. Encountered 'Text'  with name '', namespace ''.

This is third party API so I cannot change the response.

Concinnity answered 13/5, 2013 at 13:33 Comment(0)
C
21

The detail node of the message fault is expected to contain XML. The GetDetail will deserialize this XML into the given object.

As the contents is not XML it was possible to use this method.

You can however get access to the XML and read the innerXml value:

MessageFault msgFault = ex.CreateMessageFault();
var msg = msgFault.GetReaderAtDetailContents().Value;

This approached worked.

Concinnity answered 13/5, 2013 at 13:50 Comment(2)
Still have an issue when the response contains angle brackets []Concinnity
this code if detail is not a string is ok: MessageFault msgFault = ex.CreateMessageFault(); XmlReader readerAtDetailContents = msgFault.GetReaderAtDetailContents(); var readOuterXml = readerAtDetailContents.ReadOuterXml(); var data = XElement.Parse(readOuterXml); Dictionary<string, string> element = data.Elements() .ToDictionary(elementKey => elementKey.Name.LocalName, elementVal => elementVal.Value, null);Nakesha
N
9

Here's a few methods I've found of extracting that detailed exception information from FaultExceptions

Get the String Contents of a Single Element

catch (FaultException e)
{
    var errorElement = XElement.Parse(e.CreateMessageFault().GetReaderAtDetailContents().ReadOuterXml());
    var errorDictionary = errorElement.Elements().ToDictionary(key => key.Name.LocalName, val => val.Value);
    var errorMessage = errorDictionary?["ErrorMessage"];
}

Example Output:

Organization does not exist.

Get the String Contents of a All Details as a Single String

catch (FaultException e)
{
    var errorElement = XElement.Parse(e.CreateMessageFault().GetReaderAtDetailContents().ReadOuterXml());
    var errorDictionary = errorElement.Elements().ToDictionary(key => key.Name.LocalName, val => val.Value);
    var errorDetails = string.Join(";", errorDictionary);
}

Example Output:

[ErrorMessage, Organization does not exist.];[EventCode, 3459046134826139648];[Parameters, ]

Get the String Contents of a Everything as an XML string

var errorElement = XElement.Parse(e.CreateMessageFault().GetReaderAtDetailContents().ReadOuterXml());
var xmlDetail = (string)errorElement;

Example Output:

<FaultData xmlns="http://schemas.datacontract.org/2004/07/Xata.Ignition.Common.Contract" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <ErrorMessage>Organization does not exist.</ErrorMessage>
    <EventCode>3459046134826139648</EventCode>
    <Parameters i:nil="true" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"></Parameters>
</FaultData>
Nica answered 11/7, 2019 at 16:35 Comment(0)
N
3

The following should give you the value of the detail element of the FaultException.

var faultMessage = faultException.CreateMessageFault();
if(faultMessage.HasDetail){
  Console.Write(faultMessage.GetDetail<XElement>().Value);
}
Nitrogen answered 30/10, 2015 at 10:26 Comment(0)
F
2
   public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {

        if (reply.IsFault)
        {
            // Create a copy of the original reply to allow default WCF processing
            MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
            Message copy = buffer.CreateMessage();  // Create a copy to work with
            reply = buffer.CreateMessage();         // Restore the original message 

            MessageFault faultex = MessageFault.CreateFault(copy, Int32.MaxValue); //Get Fault from Message
            FaultCode codigo = faultex.Code;
            //if (faultex.HasDetail)... //More details

            buffer.Close(); 
Forelady answered 13/5, 2015 at 7:59 Comment(1)
Could you also add some commentary?Trustworthy
O
0

You can catch FaultException<TDetail>, which gives you detail for free.

catch (FaultException<string> ex)
{
    string yourDetail = ex.Detail;
}
Oxen answered 30/7, 2020 at 11:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.