Удаление пространства имен из запроса SOAP - PullRequest
10 голосов
/ 11 ноября 2010

Я импортировал WSDL и использую его для отправки SOAP-запроса. Это выглядит так:

<?xml version="1.0"?>
<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">
    <SOAP-ENV:Body>
        <Calculate xmlns="urn:xx.WSDL.xxxxxWebService">
            <ContractdocumentIn>
                <AL>
                ...More XML...

Проблема заключается в части xmlns="urn:xx.WSDL.xxxxxWebService" в элементе Calculate. Веб-сервис не может принять это. Веб-сервису не нравятся такие пространства имен ...
Используя SoapUI Я обнаружил, что этот запрос работает нормально:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:col="http://example.com.service.xxx/">
    <SOAP-ENV:Body>
        <col:Calculate>
            <ContractdocumentIn>
                <AL>
                    ...More XML...

Итак, как мне изменить запрос с первой версии на вторую? (Без использования грязных трюков!)
(Повторный импорт не проблема, если это приведет к правильному формату запроса.)




Опять же: недопустимые хитрости, такие как взлом потока запросов для его изменения!


И хотя я еще не полностью протестировал его, похоже, что C # / VS2010 и Delphi 2010 также не могут использовать веб-сервис, который я пытаюсь вызвать. Веб-сервис, который, кажется, написан на Java. SoapUI написан на Java, поэтому у нас есть Java-клиент, взаимодействующий с Java-сервисом, который, кажется, работает нормально. Но любой другой клиент?
В любом случае, пришло время добавить еще два тега: «Java», так как это сервис Java, и «vs2010», потому что .NET также не нравится этот сервис.
И я собирался написать обертку вокруг этого сервиса в .NET, надеясь, что это сработает ... Это не так. Так что это очень серьезный недостаток, возможно, недостаток Java ...

Ответы [ 2 ]

14 голосов
/ 16 ноября 2010

Если служба ожидает:

  <col:Calculate>
     <ContractdocumentIn>
         <AL>

и Delphi SOAP отправляет ...

    <Calculate xmlns="urn:xx.WSDL.xxxxxWebService">
        <ContractdocumentIn>
            <AL>

... проблема в том, что ContractdocumentIn является неквалифицированным элементом и (до Delphi XE) Delphi SOAP не поддерживал неквалифицированные элементы, которые являются элементами операции верхнего уровня. Элементы верхнего уровня являются параметрами функции, и негде хранить тот факт, что базовый элемент должен быть неквалифицированным; для элементов, которые отображаются на свойства, мы используем индекс свойства, чтобы сохранить флаг IS_UNQL.

Кстати, нет необходимости использовать префикс. Служба также принимает (должна):

    <Calculate xmlns="urn:xx.WSDL.xxxxxWebService">
        <ContractdocumentIn xmlns="">
            <AL>

Последний более многословен, но он эквивалентен префиксному случаю.

В Delphi XE импортер хранит в памяти тот факт, что определенный параметр отображается на неквалифицированный элемент, и среда выполнения воздействует на эту информацию. Я опубликовал патчи, основанные на реализации XE для D2010 и D2007, в группе новостей, когда она недавно появилась в теме:

https://forums.embarcadero.com/thread.jspa?threadID=43057

Если кому-то нужен доступ к ним (они были в области вложений, но могли быть прокручены), пожалуйста, напишите мне, и я сделаю их доступными. [bbabet at embarcadero dot com]

Приветствия

Брюно

8 голосов
/ 14 ноября 2010

OMG! Потребовалось много кофе и много недосыпания, но мне удалось решить мою проблему! Это тоже довольно просто ...
Сначала я импортирую WSDL, как и ожидалось. Это сгенерирует несколько TRemotable классов. Затем для каждого TRemotable, которому требуется другое пространство имен, я переопределяю метод ObjectToSOAP ()! (И включите XMLIntf в источник WSDL.) В моем случае с кодом, подобным этому, для нескольких типов, которые можно удалить:

function AL2.ObjectToSOAP( RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const NodeName, NodeNamespace, ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString ): IXMLNode;
begin
  Result := inherited ObjectToSOAP( RootNode, ParentNode, ObjConverter, NodeName, '', '', ObjConvOpts, RefID );
end;

Который работал в Delphi XE. В Delphi 2007 мне пришлось использовать модули XMLIntf и XMLDoc плюс этот код для типа ввода:

function ContractdocumentInType.ObjectToSOAP(RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const Name, URI: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString): IXMLNode;

  procedure AlterChildren(Child: IXMLNode);
  var
    I: Integer;
  begin
    if (Child.NodeType = ntElement) then Child.SetAttributeNS('xmlns', '', '');
    for I := 0 to Pred(Child.ChildNodes.Count) do
      AlterChildren(Child.ChildNodes[I]);
  end;

begin
  Result := inherited ObjectToSOAP(RootNode, ParentNode, ObjConverter, Name, '', ObjConvOpts, RefID);
  AlterChildren(Result);
end;

Это хак, на мой взгляд. Но это не очень грязный. Это немного экспериментирует, собирая запросы и ответы SOAP, чтобы проверить их содержимое и посмотреть, использует ли он правильные пространства имен. К сожалению, Delphi XE справляется с этим намного лучше, чем Delphi 2007.

Тем не менее, я оставляю этот вопрос открытым для любых лучших решений ...


Кстати, чтобы добавить col: к выводу, мне также пришлось изменить эту строку в WSDL RemClassRegistry.RegisterXSClass(Calculate, 'http://colan.ogconnect.service.wzp/', 'Calculate'); на эту: RemClassRegistry.RegisterXSClass(Calculate, 'http://colan.ogconnect.service.wzp/', 'cal:Calculate');. Результат тогда становится <cal:Calculate xmlns:cal="http://example.webservice/">. Однако больше ничего не нужно делать: переместить этот xmlns:cal в заголовок xml. Но как сейчас, это работает для меня.


Еще одно примечание: для WSDL я использовал следующие настройки: «One Outparam is return», «Разматывать литеральные параметры», «Создать деструкторы», «Предупреждающие комментарии», « испускать литеральные типы », «Отобразить строку в широкую строку». Другие варианты: «Создать подробную информацию о типах и интерфейсах», «Игнорировать типы портов с помощью HTTP-привязок», «Проверять элементы перечисления», «Импортировать типы ошибок», «Импортировать типы заголовков», «Обработать включенные и импортированные схемы», «Создать» псевдоним класса как типы классов ',' параметры Allow Out 'и' Process nillable и необязательные элементы '. Литеральные типы emit были практичны, потому что они генерируют класс вокруг единственного метода, который я вызывал. К сожалению, это тоже мало поможет, хотя класс поможет вам изменить запрос SOAP на верхнем уровне в конверте, переопределив метод ObjectToSOAP ().
Создание самого конверта находится в модуле SOAPEnv и он используется в модуле OPToSOAPDomConv. К сожалению, я не нашел простого способа получить доступ к самому конверту, чтобы изменить заголовок и добавить это дополнительное пространство имен. С другой стороны, я мог бы переопределить класс TSOAPDomConv своей собственной версией, которая добавляет дополнительное пространство имен. Но код работает для меня сейчас, и, как сказал мне мой отец, когда он научил меня программировать: никогда не исправляйте ничего, что не сломалось.

...