Array_Of_Int в SOAP-клиенте - PullRequest
       1

Array_Of_Int в SOAP-клиенте

2 голосов
/ 23 февраля 2011

У меня очень интересная проблема, когда я вызываю метод SOAP с моим клиентом, я должен передать параметр, который имеет тип Array_Of_Int (Array_Of_Int = array of Integer), проблема заключается в том, что, когда массив генерируется в запросе , он генерирует следующее

<ArrayParam>
  <item>12345</item>
  <item>23456</item>
  <item>34567</item>
</ArrayParam>

но я полагаю, что сервер ожидает

<ArrayParam>12345</ArrayParam>
<ArrayParam>23456</ArrayParam>
<ArrayParam>34567</ArrayParam>

Я почти уверен, что Delphi как-то обходит эту проблему в RegisterSerializeOptions или RegisterInvokeOptions, однако, похоже, я не могу найти проблему, мысли?!

Спасибо всем за потраченное время, я использую Delphi 2010.

РЕДАКТИРОВАТЬ: чтобы исправить эту проблему, как упомянул Бруно, нам нужно добавить следующий код в раздел инициализации сгенерированного файла .pas:

InvRegistry.RegisterInvokeOptions(TypeInfo(<ServerInterfaceNameHere>), ioDocument);

Однако это вызывает еще одну проблему - пространство имен, поскольку это быстрое и довольно элегантное исправление. Я добавил следующий код в метод OnBeforeExecute THTTPRio

procedure TMyDataModule.MyRioBeforeExecute(const MethodName: string; SOAPRequest: TStream);

  procedure FixNamespaces;
  var
    LStrings: TStringList;
  begin
    LStrings := TStringList.Create;
    try
      SOAPRequest.Position := 0;
      LStrings.LoadFromStream(SOAPRequest);
      SOAPRequest.Position := 0;
      SOAPRequest.Size := 0;
      LStrings.Text := StringReplace(LStrings.Text, MethodName, 'NS1:' + MethodName, [rfReplaceAll]);
      LStrings.Text := StringReplace(LStrings.Text, MethodName + ' xmlns', MethodName + ' xmlns:NS1', []);
      LStrings.SaveToStream(SOAPRequest);
      SOAPRequest.Position := 0;
    finally
      FreeAndNil(LStrings);
    end; // tryf
  end; // procedure FixNamespaces;

begin
  FixNamespaces;
end;

Выше приведено просто исправление, я действительно надеюсь, что смогу найти более чистое и элегантное решение этой проблемы, если кто-нибудь знает, пожалуйста, отправьте свой ответ .

Ответы [ 2 ]

4 голосов
/ 23 февраля 2011

Два описанных вами варианта сериализации являются действительными и необходимыми. Проблема в том, что с языковой / нативной точки зрения Delphi представляет их обоих динамическим массивом (Array_Of_Int = массив Integer). Таким образом, среде выполнения необходимо указать, следует ли сериализовать «Чистую коллекцию» (первый вид с элементами и внешним ArrayParam) или «неограниченные элементы» (элементы «ArrayParam»).

В более ранних версиях, включая 2010, вы могли указать среде выполнения сериализоваться как неограниченные элементы со следующей регистрацией:

  RemClassRegistry.RegisterSerializeOptions(TypeInfo(Array_Of_Int), [xoInlineArrays]);

Если тип используется в свойстве, вы также можете просто пометить само свойство как неограниченное, как в:

property propName: Array_Of_Int Index (IS_UNBD) read FName write FName;

Недостаток подхода регистрации состоит в том, что он не позволяет (повторно) использовать тип для обеих сериализаций. В Delphi XE это было исправлено, и теперь тип никогда не регистрируется для конкретной схемы. Вместо этого каждое свойство или параметр Dynamic Array указывает, является ли это «Чистая коллекция» или «Неограниченный элемент», устраняя необходимость иметь отдельный динамический массив целых чисел для каждой сериализации.

Приветствия

Брюно

1 голос
/ 25 февраля 2011

Поскольку никто не хочет публиковать свой ответ или не имеет никакой другой идеи о том, как решить эту проблему, я просто опубликую свое исправление, пока другие не смогут предложить более элегантное решение, чем редактирование запроса.

Убедитесь, что следующая строка кода добавлена ​​в раздел инициализации файла * .pas, сгенерированного при импорте файла WSDL (большое спасибо Бруно за указание на это)

InvRegistry.RegisterInvokeOptions(TypeInfo(<ServerInterfaceNameHere>), ioDocument);

Однако это вызывает еще одну проблему - пространство имен, поскольку это быстрое и довольно элегантное исправление. Я добавил следующий код в метод OnBeforeExecute THTTPRio

procedure TMyDataModule.MyRioBeforeExecute(const MethodName: string; SOAPRequest: TStream);

  procedure FixNamespaces;
  var
    LStrings: TStringList;
  begin
    LStrings := TStringList.Create;
    try
      SOAPRequest.Position := 0;
      LStrings.LoadFromStream(SOAPRequest);
      SOAPRequest.Position := 0;
      SOAPRequest.Size := 0;
      LStrings.Text := StringReplace(LStrings.Text, MethodName, 'NS1:' + MethodName, [rfReplaceAll]);
      LStrings.Text := StringReplace(LStrings.Text, MethodName + ' xmlns', MethodName + ' xmlns:NS1', []);
      LStrings.SaveToStream(SOAPRequest);
      SOAPRequest.Position := 0;
    finally
      FreeAndNil(LStrings);
    end; // tryf
  end; // procedure FixNamespaces;

begin
  FixNamespaces;
  // other possible issue to be fixed -- if any
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...