Возможно ли использовать неправильно сформированные сообщения об ошибках?
-
03-07-2019 - |
Вопрос
У меня есть клиент WCF, взаимодействующий с неизвестной серверной реализацией, которую я не могу контролировать. Этот клиент работает нормально, ему просто не нравятся неправильные сообщения SOAP Fault. Сообщения, которые я получаю, выглядят так:
<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>
Я считаю, что в соответствии со схемой мыла дочерние элементы не должны быть квалифицированы и должны выглядеть следующим образом:
<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>
Есть ли что-то, что я могу настроить или переопределить, чтобы я мог использовать сообщения, поступающие в последнем формате, чтобы я мог использовать сообщения об ошибках вместо исключений xml?
Решение
Я не могу вспомнить, как я наткнулся на инспекторов сообщений, но именно так я решил свою проблему.
Это и эта статья послужила основой для создания инспектора, и что следует за мясом инспектора:
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; }
Другие советы
Похоже, что приложение-нарушитель использует собственную (и плохо реализованную) библиотеку SOAP. Следующая статья может помочь (мне еще не приходилось сталкиваться с этим, так как я нахожусь в чистом магазине .Net).
Обратите внимание, что класс System.Web.Services.Protocols.SoapHttpClientProtocol кажется значительно более терпимым к неверно сформированным ответам Fault, чем WCF.
Это иногда называют протоколом обслуживания ASMX. Это тоже можно рассмотреть.
Говард Хоффман
} catch (SoapFaultClientException e) {
log.error(e);
SoapFaultDetail soapFaultDetail = e.getSoapFault().getFaultDetail();
SoapFaultDetailElement detailElementChild = (SoapFaultDetailElement) soapFaultDetail.getDetailEntries().next();
Source detailSource = detailElementChild.getSource();
try {
Object detail = (JAXBElement<SearchResponse>) getWebServiceTemplate().getUnmarshaller().unmarshal(detailSource);
// throw new SoapFaultWithDetailException(detail);
} catch (IOException e1) {
throw new IllegalArgumentException("cannot unmarshal SOAP fault detail object: " + soapFaultDetail.getSource());
}
}