Несколько пространств имен в сообщении об ошибке мыла приводят к сбою десериализации FaultException

Мы подключаемся к веб-службе, и сообщение об ошибке, которое мы получаем, не десериализуется (вообще), и никакая версия класса, которую я могу сделать, не будет десериализоваться правильно. У нас нет контроля над серверной частью вещей. Сервер не разрешает обнаружение, поэтому добавление ?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


person Tangurena    schedule 17.09.2009    source источник
comment
возможная двойная ошибка stackoverflow.com/questions/4140030/ stackoverflow.com/questions/9463802/   -  person Ruskin    schedule 23.06.2014


Ответы (3)


В итоге мы отказались от попыток поймать ошибку и передали ее обратно по каналу 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)
{
// Здесь обрабатывается исключение.
}

Слишком много времени было потрачено впустую на исправление пространств имен. Спасибо за ответ.

person Tangurena    schedule 25.09.2009

Один из способов справиться с этим, если сериализация полностью завершается сбоем, — использовать OoperationContract с использованием Сообщение в качестве входных и выходных данных. Таким образом, вы можете вручную проанализировать XML, когда Ifault == true, или использовать GetBody() для получения обычного содержимого, если не произошло ошибки.

person Maurice    schedule 18.09.2009

Прежде всего, если вы не можете получить WSDL от людей, создавших эту веб-службу, то им нечего делать с веб-службой на основе SOAP. Правильный WSDL решит вашу проблему, независимо от того, используется ли «?WSDL».

Во-вторых, опубликуйте код класса eGov2ExceptionType. Я подозреваю, что на нем не установлено пространство имен http://eGov.gov.

person John Saunders    schedule 19.09.2009
comment
WSDL были разосланы квалифицированным партнерам, одним из которых мы являемся. В понедельник я выложу код самого близкого класса, который я сделал. - person Tangurena; 20.09.2009
comment
Если у вас есть WSDL, вы сможете предоставить его svcutil.exe и получить то, что вам нужно. Попробуйте это и посмотрите, выдает ли svcutil какие-либо сообщения об ошибках или предупреждения. Если ничего не отображается, то посмотрите в сгенерированных классах — иногда предупреждения появляются в виде комментариев в сгенерированном коде. - person John Saunders; 24.09.2009