Recently working with a partner I came across a solution for a limitation in WCF error handling.  The root of the issue is a difference between SOAP 1.1 and SOAP 1.2 in the allowed HTTP status codes when a SOAP fault is returned.  For SOAP 1.1, the status code must be 500 “Internal Server Error”.  For SOAP 1.2, it varies based on the type of the SOAP fault.  For env:Sender, the status code is 400 “Bad Request”, but for anything else it is 500 like SOAP 1.1.

When WCF receives an HTTP error code it wraps it in an exception, FaultException in the case of 500 and ProtocolException in the case of 400.  This means when a service returns a SOAP fault with a 400 status code, all the information about it is lost instead of showing up in a nicely populated FaultException.  Actually it isn’t lost, it’s just hidden.  The InnerException of the ProtocolException is a WebException generated by the HTTP response.  And on the WebException, lo and behold, is the the actual WebResponse with that SOAP fault just waiting to be read out of the stream.  So with a little manipulation you can turn these ProtocolExceptions into FaultExceptions:

   1: static FaultException ParseProtocolExecption(ProtocolException ex)
   2: {
   3:     try
   4:     {
   5:         System.IO.Stream stream = (ex.InnerException as WebException).Response.GetResponseStream();
   6:         System.Xml.XmlReader xmr = System.Xml.XmlReader.Create(stream);
   7:         Message message = Message.CreateMessage(xmr, (int)stream.Length, MessageVersion.Soap12);
   8:         MessageFault mf = MessageFault.CreateFault(message, (int)stream.Length);
   9:         FaultException fe = new FaultException(mf);
  10:         message.Close();
  11:         return fe;
  12:     }
  13:     catch (Exception)
  14:     {
  15:         return new FaultException(ex.Message);
  16:     }
  17: }

Note if there isn’t a SOAP fault in the response, this will throw again, you’ll want to handle that in the best way for your application.