Подтвердить что ты не робот

Delphi SOAP Envelope и WCF

Я работаю над системой, которая предоставляет интерфейс мыла. Одна из систем, которые будут использовать интерфейс, кодируется в Delphi 7. Веб-служба разработана с использованием WCF, базовой привязки HTTP, SOAP 1.1.

Если я использую SOAP UI (JAVA), служба работает правильно. Но Delphi, кажется, делает особые вещи здесь;)

Вот как выглядит сообщение в интерфейсе SOAP:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.xxx.de/xxx">
   <soapenv:Header/>
   <soapenv:Body>
      <ser:GetCustomer>
         <!--Optional:-->
         <ser:GetCustomerRequest> <!-- this is a data contract -->
            <ser:Id>?</ser:Id>
         </ser:GetCustomerRequest>
      </ser:GetCustomer>
   </soapenv:Body>
</soapenv:Envelope>

Я не разработчик delphi, но я разработал простой тестовый клиент, чтобы понять, что происходит. Это то, что Delphi отправляет как конверт SOAP.

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:NS2="http://services.xxx.de/xxx">
    <NS1:GetCustomer xmlns:NS1="http://services.xxx.de/xxx">
      <GetCustomerRequest href="#1"/>
    </NS1:GetCustomer>
    <NS2:GetCustomerRequest id="1" xsi:type="NS2:GetCustomerRequest">
      <Id xsi:type="xsd:int">253</Id>
    </NS2:GetCustomerRequest>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

WCF выдает ошибку, которая находится на немецком языке...;)

Es wurde das Endelement "Body" aus Пространство имен " http://schemas.xmlsoap.org/soap/envelope/" erwartet. Gefunden wurde "Элемент" NS2: GetCustomerRequest "aus Namespace" http://services.xxx.de/xxx "". Zeile 1, Позиция 599.

Значит что-то вроде

Ожидалось Тело. Но вместо этого был найден элемент "NS2: GetCustomerReques".

Теперь мои вопросы: могу ли я как-то изменить способ создания Delphi конверта? Или способы заставить WCF работать с такими форматами сообщений? Любая помощь очень ценится!

4b9b3361

Ответ 1

В отличие от того, что некоторые люди здесь кажутся подразумевающими, Delphi не отправляет неверный SOAP, он просто отправляет SOF файл RPC/Encoded. Очень легко распознать все атрибуты xsi:type. RPC/Encoded не соответствует WS-I, но он по-прежнему действует SOAP.

WCF по умолчанию использует формат SOA Document/Literal/Wrapped, который Delphi 7 не может обрабатывать вообще на стороне сервера, и вы должны внести некоторые корректировки на стороне клиента.

Самое простое решение - просто сказать Delphi использовать стиль Document/Literal. Вы делаете это, включив soLiteralParams в THttpRio.Converter.Options. Это говорит, что Delphi не "разматывает" параметры, которые вы видите. Аспект "Документ" - это то, что обычно может определить импортер Delphi WSDL, поэтому вам не стоит беспокоиться об этом.

Другое решение - сообщить службе WCF использовать стиль RPC/Encoded, который вы можете сделать, добавив следующие атрибуты в службу:

[ServiceContract]
[XmlSerializerFormat(Style = OperationFormatStyle.Rpc,
    Use = OperationFormatUse.Encoded)]
public interface IMyService
{
    // etc.
}

Второе не рекомендуется, поскольку, как я уже упоминал ранее, RPC/Encoded не совместим с WS-I, но, тем не менее, большинство инструментов SOAP его распознают, поэтому я перечисляю его здесь как возможность.

Ответ 2

Я только что сделал один из них, и я закончил серию вызовов stringreplace, чтобы изменить мой XML-вывод, чтобы удалить потоковые пространства имен и сделать его похожим на формат SoapUI. Да, для этого требуется много ручного взлома.

Пример:

После создания RIO вызовите собственный процесс BeforeExecute:

...
 EEUPSERTRIO.OnBeforeExecute := self.RIO_BeforeExecute;
...

procedure TMyWrapper.RIO_BeforeExecute(const MethodName: string; var SOAPRequest: WideString);
{
Since Delphi isn't very good at SOAP, we need to fix the request so that the namespaces are correct.
Basically, you take what Delphi gives you and try it in SoapUI.
If yours doesn't work and SoapUI version does, make yours look like theirs.
}

... Теперь выделите поточные пространства имен:

SOAPRequest := StringReplace(SOAPRequest,' xmlns:NS1="http://services.xxx.de/xxx"','',[rfReplaceAll,rfIgnoreCase]);

... Многие из них.

Затем вы замените заголовок мыла тем, который содержит требуемые пространства имен.

SOAPRequest := StringReplace(SOAPRequest,'xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"','xmlns:ns1="http://services.xyzcorp.com/xyz/EnterpriseEmployeeService_1_0" '+'xmlns:ns1="http://schemas.xyzcorp.com/TLOIntegration_HRO_Preview/TLOIntegration_1_0" ',[]);

Затем вы можете повторно вставить хорошие:

  ReplaceTag(SOAPRequest,'<metaData>','ns1:');
  ReplaceTag(SOAPRequest,'<trackingId>','ns1:');
  ReplaceTag(SOAPRequest,'<srcSystem>','ns1:');

Наконец, вы можете легко захватить свой вывод Delphi, повторно потребляя WSDL с помощью SoapUI и имея в своем распоряжении mockservice. Затем укажите свое приложение в качестве конечной точки, и оно будет захватывать вывод.
Или вы можете использовать Fiddler в качестве прокси-сервера для захвата запросов.

Ответ 3

В инфраструктурах Delphi и Java используется другое пространство имен. Один из способов сделать совместимым - перехватить необработанный xml и изменить все "NS2" на то, что ожидает deserializer

Приветствия