SOAP客户端中的Array_Of_Int

时间:2011-02-23 10:28:18

标签: delphi soap

当我用我的客户端调用SOAP方法时,我有一个非常有趣的问题,我必须传递一个类型为Array_Of_Int的参数(Array_Of_Int = 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。

编辑:为了解决这个问题,正如Bruneau所说,我们需要在生成的.pas文件的初始化部分添加以下代码:

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

然而,这又引发了另一个问题,命名空间,作为一个快速而优雅的修复,我在THTTPRio的OnBeforeExecute方法中添加了以下代码

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 个答案:

答案 0 :(得分:4)

您描述的两个序列化选项都是有效且必需的。问题是从语言/本地的角度来看,Delphi用动态数组表示它们(Array_Of_Int = Integer数组)。因此,必须告知运行时是否序列化为“Pure Collection”(第一种带有元素和外部ArrayParam)或“无界元素”(“ArrayParam”元素)。

在早期版本(包括2010)中,您可以通过以下注册指示运行时序列化为无界元素:

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

如果在属性中使用了类型,您还可以简单地将属性本身标记为无界,如:

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

注册方法的缺点是它不允许(重新)使用该类型进行两个序列化。在Delphi XE中,这已得到补救,现在该类型从未在特定方案中注册。相反,每个动态数组属性或参数都指定它是“纯集合”还是“无界元素”,从而无需为每个序列化使用不同的动态整数数组。

干杯,

布诺

答案 1 :(得分:1)

由于没有人愿意发布他们的答案或对如何解决这个问题没有其他想法,我只会发布我的修复,直到其他人能够提出比编辑请求更优雅的解决方案。

确保在导入WSDL文件时生成的* .pas文件的初始化部分中添加了下一行代码(非常感谢Bruneau指出这一点)

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

然而,这又引发了另一个问题,命名空间,作为一个快速而优雅的修复,我在THTTPRio的OnBeforeExecute方法中添加了以下代码

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;