Receiving unsecured response with WCF – Revisted

A while back I blogged about how to deal with unsecured responses in WCF (see this post). I’ve had several people ask me for the code that you can use in case you can’t use the mentioned hotfix. Attached is the code for a message encoder that intercepts the MessageSecurityException thrown by the original encoder. The encoder wraps around the actual encoder you want to use, so you’ll have to configure it like this:

<system.serviceModel>
  <extensions>
    <bindingElementExtensions>
      <add name="unsecureResponseEncoding"
           type="UnsecureResponseEncoder.InterceptingMessageEncodingElement, UnsecureResponseEncoder,
                 Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </bindingElementExtensions>
  </extensions>
  <bindings>
    <customBinding>
      <unsecureResponseEncoding>
        <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
                             messageVersion="Soap11WSAddressing10">
          <readerQuotas maxDepth="32" maxStringContentLength="8192"
                        maxArrayLength="16384" maxBytesPerRead="4096"
                        maxNameTableCharCount="16384" />
        </textMessageEncoding>
      </unsecureResponseEncoding>
    <!-- removed for briefity -->
    </customBinding>
  </bindings>
  <client>
    <!-- removed for briefity -->
  </client>
  <behaviors>
    <!-- removed for briefity -->
  </behaviors>
</system.serviceModel>

The main thing the UnsecureResponseEncoder does is override the ReadMessage methods of the message encoder. All else is just plumbing to wrap the original encoder and use it as is. In ReadMessage the received message is retrieved and place in a local variable. If a MessageSecurityException occurs, this is caught, and an UnecureResponseException is thrown, which includes the original message. Higher up in the call chain you can parse the original message and extract the fault information. The example below shows an altered proxy call so the proxy actually returns a FaultException<>.

SomeResponseMessageContract ISomeService.SomeServiceMethod(SomeRequestMessageContract request)
{
    try
    {
        return base.Channel.Aanleveren(request);
    }
    catch (UnsecureResponseException exception)
    {
        if (String.IsNullOrEmpty(exception.ResponseMessage) == false)
        {
            // Put original response message in XmlDocument so you can manipulate it
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(exception.ResponseMessage);

            // Add namespaces concerning faults, including your custom fault schema
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(xml.NameTable);
            nsmgr.AddNamespace(“soapenv”, “http://schemas.xmlsoap.org/soap/envelope/”);
            nsmgr.AddNamespace(“fault”, “http://somefaultschema/”);

            // Retrieve the fault node and extract information.
            XmlNode faultNode = xml.SelectSingleNode(“/soapenv:Envelope/soapenv:Body/soapenv:Fault”, nsmgr);
            if(faultNode != null)
            {
                SomeFault fault = new SomeFault()
                {
                    SomeFaultInfo = faultNode.GetNodeStringValue(“detail/fault:SomeFault/fault:SomeFaultInfo”, nsmgr)
                };
                if(String.IsNullOrEmpty(fault.SomeFaultInfo) == false)
                {
                    throw new FaultException(fault, exception.Message);
                }
            }
        }
        throw; // If not properly handled, rethrow original exception
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *