Несколько пространств имен в сообщении ошибки мыла, приводящее к сбою десериализации FaultException
-
10-07-2019 - |
Вопрос
Мы подключаемся к веб-службе, и возвращаемое нами сообщение об ошибке не десериализовано (вообще), и ни одна версия класса, которую я могу создать, не будет десериализована правильно. У нас нет контроля над серверной стороной вещей. Сервер не разрешает обнаружение, поэтому добавление? WSDL в конец URL-адреса конечной точки приводит к ошибке, а не к WSDL. Р>
[Fiddler] [1] показывает, что возвращаемое сообщение об ошибке выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:eGov="http://eGov.gov" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>Client</faultcode>
<faultstring/>
<detail>
<eGov:eGov2Exception>
<eGov:ErrorClassification>SOME_ERROR</eGov:ErrorClassification>
<eGov:ErrorCode>SOME_ERROR_CODE</eGov:ErrorCode>
<eGov:ErrorMessage>Your request was unsuccessful. blah blah blah.</eGov:ErrorMessage>
</eGov:eGov2Exception>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
Тем не менее, ни один из созданных нами классов (пробующий xsd.exe, svcutil и другие, включая код, написанный с нуля) не сможет десериализовать его, когда мы попытаемся поймать его с помощью:
catch (FaultException<eGov2ExceptionType> exp)
{
// Never stops here.
}
catch (FaultException<AllOtherAttemptedClasses> exp)
{
// Never stops here.
}
catch (SoapException se)
{
// Never stops here.
}
catch (FaultException exp)
{
//Always gets caught here.
}
Будет вызван только базовый улов FaultException, то есть мы потеряем содержимое отправляемого сообщения FaultMessage. Некоторые из классов, которые я написал, будут сериализованы очень близко к примеру выше, но не смогут его десериализовать, поэтому мы подозреваем, что существует проблема с пространством имен. Р>
Вопросы:
1 - Как бы вы это написали?
2 - Это распространенная ошибка / проблема с WCF?
[1]: http://www.fiddler2.com/fiddler2/ Fiddler р>
Решение
В итоге мы перестали пытаться поймать Fault и передать его обратно в канал SOAP. Вместо этого мы создали собственное исключение и подключили MessageInspector , чтобы отслеживать ошибки и выдавать его как исключение. Р>
Соответствующая часть (санированная) кода:
public void AfterReceiveReply(ref Message reply, object correlationState)
{
if (reply.IsFault)
{
XmlDictionaryReader xdr = reply.GetReaderAtBodyContents();
XNode xn = XDocument.ReadFrom(xdr);
string s = xn.ToString();
XDocument xd = XDocument.Parse(s);
XNamespace nsSoap = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace ns = "http://eGov.gov";
XElement xErrorClass = xd.Element(nsSoap + "Fault").Element("detail").Element(ns + "eGov2Exception").Element(ns + "RequestErrorClassification");
XElement xErrorCode = xd.Element(nsSoap + "Fault").Element("detail").Element(ns + "eGov2Exception").Element(ns + "RequestErrorCode");
XElement xErrorMessage = xd.Element(nsSoap + "Fault").Element("detail").Element(ns + "eGov2Exception").Element(ns + "RequestErrorMessage");
throw new eGovException(xErrorClass.Value, xErrorCode.Value, xErrorMessage.Value);
}
}
Затем основное приложение использует:
catch (eGovException ex)
{
// Здесь обрабатывается исключение.
} Р>
Слишком много времени было потрачено впустую, пытаясь исправить пространства имен. Спасибо за ответы. Р>
Другие советы
Один из способов справиться с этим, если сериализация завершается сбоем, - это использовать OoperationContract, используя Тип сообщения в качестве ввода и вывода. Таким образом, вы можете вручную проанализировать XML, когда Iffault == true, или использовать GetBody (), чтобы получить обычное содержимое, если не было ошибок.
Прежде всего, если вы не можете получить WSDL от людей, создавших этот веб-сервис, то у них нет бизнеса, имеющих веб-сервис на основе SOAP. Надлежащий WSDL решит вашу проблему, независимо от того, «WSDL» или нет; используется.
Во-вторых, опубликуйте код класса eGov2ExceptionType
. Я подозреваю, что на нем не установлено пространство имен http://eGov.gov
.