I've a WCF client communicating with an unknown server implementation which I have no control over. This client works fine it just doesn't like, what appears to be, incorrectly formed SOAP Fault messages. The messages I receive look like:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header>...</soap:Header> <soap:Body> <soap:Fault> <soap:faultcode>soap:Client</soap:faultcode> <soap:faultstring>...</soap:faultstring> <soap:detail>...</soap:detail> </soap:Fault> </soap:Body> </soap:Envelope>
I believe according to the soap schema the child elements shouldn't be qualified and ned to look like:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header>...</soap:Header> <soap:Body> <soap:Fault> <faultcode>soap:Client</faultcode> <faultstring>...</faultstring> <detail>...</detail> </soap:Fault> </soap:Body> </soap:Envelope>
Is there something that I can configure or override so that I can consume messages which arrive in the latter format so that I can consume the fault messages instead of xml exceptions?
I'm cannot recall how I found stumbled across Message Inspectors, but that it how I solved my problem.
This and this article provided the base for creating the inspector, and what follows is the meat of the inspector:
public void AfterReceiveReply(ref Message reply, object correlationState) { if (!reply.IsFault) return; var document = new XmlDocument(); document.Load(reply.GetReaderAtBodyContents()); var navigator = document.CreateNavigator(); var manager = new XmlNamespaceManager(navigator.NameTable); manager.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/"); var it = navigator.Select("//soap:Fault", manager); if (it.MoveNext() && it.Current.HasChildren && it.Current.MoveToChild(XPathNodeType.Element)) { do { var c = it.Current; if (string.IsNullOrEmpty(c.Prefix)) continue; c.ReplaceSelf("<" + c.LocalName + ">" + c.InnerXml + "</" + c.LocalName + ">"); /// we may want to record the detail included inside the detail element, /// it is not reported in the FaultException that is raised. } while (it.Current.MoveToNext()); } var reader = XmlDictionaryReader.CreateDictionaryReader(new XmlNodeReader(document)); reader.MoveToStartElement(); var fixedReply = Message.CreateMessage(reply.Version, null, reader); fixedReply.Headers.CopyHeadersFrom(reply.Headers); fixedReply.Properties.CopyProperties(reply.Properties); reply = fixedReply; }