Конверт Delphi SOAP и WCF - PullRequest
       23

Конверт Delphi SOAP и WCF

12 голосов
/ 18 марта 2010

Я работаю в системе, которая предоставляет мыльный интерфейс. Одна из систем, которые собираются использовать интерфейс, написана на 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 "Тело" aus Namespace "http://schemas.xmlsoap.org/soap/envelope/" erwartet. Gefunden wurde" Элемент "NS2: GetCustomerRequest" aus Namespace "http://services.xxx.de/xxx"". Zeile 1, Position 599.

Означает что-то вроде

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

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

Ответы [ 3 ]

17 голосов
/ 20 марта 2010

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

WCF по умолчанию использует формат Document / Literal / Wrapped SOAP, который 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 распознают его, поэтому я перечисляю его здесь как возможность.

3 голосов
/ 19 марта 2010

Я только что сделал один из них, и я закончил серией строковых вызовов, чтобы изменить вывод 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's 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 в качестве прокси для захвата запросов.

0 голосов
/ 19 марта 2010

Платформы Delphi и Java используют другое пространство имен. Один из способов сделать его совместимым - перехватить необработанный xml и изменить все «NS2» на то, что ожидает десериализатор

Приветствия

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...