Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET WCF faults generating incorrect SOAP 1.1 faultcode values

I am experimenting with using the FaultException and FaultException<T> to determine the best usage pattern in our applications. We need to support WCF as well as non-WCF service consumers/clients, including SOAP 1.1 and SOAP 1.2 clients.

FYI: using FaultExceptions with wsHttpBinding results in SOAP 1.2 semantics whereas using FaultExceptions with basicHttpBinding results in SOAP 1.1 semantics.

I am using the following code to throw a FaultException<FaultDetails>:

  throw new FaultException<FaultDetails>(
      new FaultDetails("Throwing FaultException<FaultDetails>."),
      new FaultReason("Testing fault exceptions."),
      FaultCode.CreateSenderFaultCode(new FaultCode("MySubFaultCode"))
      );

The FaultDetails class is just a simple test class that contains a string "Message" property as you can see below.

When using wsHttpBinding the response is:

<?xml version="1.0" encoding="utf-16"?>
<Fault xmlns="http://www.w3.org/2003/05/soap-envelope">
<Code>
  <Value>Sender</Value>
  <Subcode>
    <Value>MySubFaultCode</Value>
  </Subcode>
</Code>
<Reason>
  <Text xml:lang="en-US">Testing fault exceptions.</Text>
</Reason>
<Detail>
  <FaultDetails xmlns="http://schemas.datacontract.org/2004/07/ClassLibrary" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <Message>Throwing FaultException&lt;FaultDetails&gt;.</Message>
  </FaultDetails>
</Detail>

This looks right according to the SOAP 1.2 specs. The main/root “Code” is “Sender”, which has a “Subcode” of “MySubFaultCode”. If the service consumer/client is using WCF the FaultException on the client side also mimics the same structure, with the faultException.Code.Name being “Sender” and faultException.Code.SubCode.Name being “MySubFaultCode”.

When using basicHttpBinding the response is:

<?xml version="1.0" encoding="utf-16"?>
<s:Fault xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <faultcode>s:MySubFaultCode</faultcode>
  <faultstring xml:lang="en-US">Testing fault exceptions.</faultstring>
  <detail>
    <FaultDetails xmlns="http://schemas.datacontract.org/2004/07/ClassLibrary" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <Message>Throwing FaultException&lt;FaultDetails&gt;.</Message>
    </FaultDetails>
  </detail>
</s:Fault>

This does not look right. Looking at the SOAP 1.1 specs, I was expecting to see the “faultcode” to have a value of “s:Client.MySubFaultCode” when I use FaultCode.CreateSenderFaultCode(new FaultCode("MySubFaultCode")). Also a WCF client gets an incorrect structure. The faultException.Code.Name is “MySubFaultCode” instead of being “Sender”, and the faultException.Code.SubCode is null instead of faultException.Code.SubCode.Name being “MySubFaultCode”. Also, the faultException.Code.IsSenderFault is false.

Similar problem when using FaultCode.CreateReceiverFaultCode(new FaultCode("MySubFaultCode")):

  • works as expected for SOAP 1.2
  • generates “s:MySubFaultCode” instead of “s:Server.MySubFaultCode” and the faultException.Code.IsReceiverFault is false for SOAP 1.1

This item was also posted by someone else on http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=669420&SiteID=1 in 2006 and no one has answered it. I find it very hard to believe that no one has run into this, yet.

Here is someone else having a similar problem: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3883110&SiteID=1&mode=1

Microsoft Connect bug: https://connect.microsoft.com/wcf/feedback/ViewFeedback.aspx?FeedbackID=367963

Description of how faults should work: http://blogs.msdn.com/drnick/archive/2006/12/19/creating-faults-part-3.aspx

Am I doing something wrong or is this truly a bug in WCF?

like image 783
wojo Avatar asked Sep 15 '08 17:09

wojo


1 Answers

This is my current workaround:

    /// <summary>
    /// Replacement for the static methods on FaultCode to generate Sender and Receiver fault codes due
    /// to what seems like bugs in the implementation for basicHttpBinding (SOAP 1.1). wsHttpBinding 
    /// (SOAP 1.2) seems to work just fine.
    /// 
    /// The subCode parameter for FaultCode.CreateReceiverFaultCode and FaultCode.CreateSenderFaultCode
    /// seem to take over the main 'faultcode' value in the SOAP 1.1 response, whereas in SOAP 1.2 the
    /// subCode is correctly put under the 'Code->SubCode->Value' value in the XML response.
    /// 
    /// This workaround is to create the FaultCode with Sender/Receiver (SOAP 1.2 terms, but gets
    /// translated by WCF depending on the binding) and an agnostic namespace found by using reflector
    /// on the FaultCode class. When that NS is passed in WCF seems to be able to generate the proper
    /// response with SOAP 1.1 (Client/Server) and SOAP 1.2 (Sender/Receiver) fault codes automatically.
    /// 
    /// This means that it is not possible to create a FaultCode that works in both bindings with
    /// subcodes.
    /// </summary>
    /// <remarks>
    /// See http://stackoverflow.com/questions/65008/net-wcf-faults-generating-incorrect-soap-11-faultcode-values
    /// for more details.
    /// </remarks>
    public static class FaultCodeFactory
    {
        private const string _ns = "http://schemas.microsoft.com/ws/2005/05/envelope/none";

        /// <summary>
        /// Creates a sender fault code.
        /// </summary>
        /// <returns>A FaultCode object.</returns>
        /// <remarks>Does not support subcodes due to a WCF bug.</remarks>
        public static FaultCode CreateSenderFaultCode()
        {
            return new FaultCode("Sender", _ns);
        }

        /// <summary>
        /// Creates a receiver fault code.
        /// </summary>
        /// <returns>A FaultCode object.</returns>
        /// <remarks>Does not support subcodes due to a WCF bug.</remarks>
        public static FaultCode CreateReceiverFaultCode()
        {
            return new FaultCode("Receiver", _ns);
        }
    }

Sadly I don't see a way to use subcodes without breaking either SOAP 1.1 or 1.2 clients.

If you use the Code.SubCode syntax, you can create SOAP 1.1 compatible faultcode values but it breaks SOAP 1.2.

If you use the proper subcode support in .NET (either via the static FaultCode methods or one of the overloads) it breaks SOAP 1.1 but works in SOAP 1.2.

like image 159
wojo Avatar answered Oct 21 '22 21:10

wojo