Passing SOAP faults from NuSoap to C#

I am currently implementing a SOAP interface for a PHP application I am working on. The built-in SOAP support in PHP didn’t really provide everything I needed (namely WSDL generation), so I went with NuSoap.
After a lot of pain trying to get a WSDL out of it, that Visual Studio would consume, and correctly parse the SOAP messages I return, I came along the next big issue today.
Whenever I tried to pass a fault from the server to my C# application, I would receive a nasty exception:

Server returned an invalid SOAP Fault. Please see InnerException for more details.

Ok, so let’s look at that InnerException:

Element ‘faultstring’ with namespace name ” was not found. Line 6, position 126.

What? No “faultstring” element? Impossible!
After double-checking my code for obvious errors and confirming with SoapUI that the “faultstring” element was indeed present, I started looking for the source of the issue. First I checked the nusoap_fault source, if there was anything weird in there that might confuse the CLR. But it seemed fine.

So I was sure the problem must be in the .Net libraries. I went on to decompile the binaries that are in use when making SOAP requests (namely System.ServiceModel). The actual issue was in System.ServiceModel.Channels.ReceivedFault.CreateFault11(). That function expects the elements of a SOAP fault’s body to be in a precise order! If the order is anything else than what it expects, it will throw the exception mentioned above.

I did not take the time to check whether this behavior is actually defined by the SOAP definition (although I highly doubt it). I just went on to extend the NuSoap classes to fix the issue. And here they are:

NuSoapServer.php:

<?php
  require_once( "nusoap/nusoap.php" );

  require_once( dirname( __FILE__ ) . "/NuSoapFault.php" );

  /**
  * Wraps a NuSoap server.
  * This class overrides the fault method of nusoap_server to use a customized version of nusoap_fault.
  */
  class NuSoapServer extends nusoap_server {
    /**
     * Specify a fault to be returned to the client.
     * This also acts as a flag to the server that a fault has occured.
     *
     * @param        string $faultcode
     * @param        string $faultstring
     * @param        string $faultactor
     * @param        string $faultdetail
     * @access   public
     */
    function fault( $faultcode, $faultstring, $faultactor='', $faultdetail='' ) {
      if( $faultdetail == "" && $this->debug_flag ) {
        $faultdetail = $this->getDebug();
      }
      $this->fault = new NuSoapFault( $faultcode, $faultactor, $faultstring, $faultdetail );
      $this->fault->soap_defencoding = $this->soap_defencoding;
    }

  }
?>

NuSoapFault.php:

<?php
  require_once( "nusoap/nusoap.php" );

  /**
  * Wraps a SOAP fault.
  * This class overrides nusoap_fault's serialize() method to fix the order in which it's members are serialized.
  * This is necessary to allow for communication with .Net clients.
  */
  class NuSoapFault extends nusoap_fault {
    /**
     * serialize a fault
     *
     * @return       string  The serialization of the fault instance.
     * @access   public
     */
    function serialize() {
      $ns_string = '';
      foreach( $this->namespaces as $k => $v ) {
        $ns_string .= "\n  xmlns:$k=\"$v\"";
      }
      $return_msg =
        '<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?>' .
        '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string . ">\n" .
          '<SOAP-ENV:Body>' .
            '<SOAP-ENV:Fault>' .
              $this->serialize_val( $this->faultcode,   'faultcode'   ) .
              $this->serialize_val( $this->faultstring, 'faultstring' ) .
              $this->serialize_val( $this->faultactor,  'faultactor'  ) .
              $this->serialize_val( $this->faultdetail, 'detail'      ) .
            '</SOAP-ENV:Fault>' .
          '</SOAP-ENV:Body>' .
        '</SOAP-ENV:Envelope>';
      return $return_msg;
    }

  }
?>

So now in my actual code I don’t use nusoap_server anymore, but my own NuSoapServer. And now everything works fine.

2 Responses to “Passing SOAP faults from NuSoap to C#”

  1. cHaOs667 Says:

    I prefer the more architectural way: Do the wsdl design before the server and client implementations happens ;)

  2. pawelgradziel Says:

    Hi,
    There is almost 1 year after your post and this topic is still actual :) You saved my day with this article! Thanks!

    It is very strange that .NET works like this. Since it is very easy to solve by just changing few lines of nusoap_fault class code I am amazed that this was not fixed already in nusoap. I posted on nusoap help forum about this here and hope they will finally fix it:
    https://sourceforge.net/projects/nusoap/forums/forum/193579/topic/4428485

    Best regards,
    PaweĊ‚

Leave a Reply

You must be logged in to post a comment.