当我与客户端调用 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。
编辑:为了解决这个问题,正如 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;
上面只是一个修复,我真的希望我能找到一个更干净和优雅的解决方案来解决这个问题,如果有人知道,请发布你的答案。
最佳答案
您描述的两个序列化选项都是有效且需要的。问题是,从语言/ native 的角度来看,Delphi 用动态数组(Array_Of_Int = 整数数组)表示它们。因此,必须告知运行时是否要序列化“纯集合”(第一种包含元素和外部 ArrayParam 的类型)还是“无界元素”(“ArrayParam”元素)。
在早期版本(包括 2010)中,您可以通过以下注册指示运行时序列化为无界元素:
RemClassRegistry.RegisterSerializeOptions(TypeInfo(Array_Of_Int), [xoInlineArrays]);
如果在属性中使用该类型,您也可以简单地将属性本身标记为无界,如下所示:
property propName: Array_Of_Int Index (IS_UNBD) read FName write FName;
注册方法的缺点是它不允许(重新)使用两种序列化的类型。在 Delphi XE 中,这个问题得到了纠正,现在该类型永远不会为特定方案注册。相反,每个动态数组属性或参数指定它是“纯集合”还是“无界元素”,从而无需为每个序列化使用不同的动态整数数组。
干杯,
布鲁诺
关于delphi - SOAP 客户端中的 Array_Of_Int,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5089633/