gpt4 book ai didi

delphi - 使用 RTTI 创建的 SOAP 请求未完全解析为 XML

转载 作者:行者123 更新时间:2023-12-03 15:34:58 25 4
gpt4 key购买 nike

在我们现在创建的新应用程序中,我们有很多 SOAP 请求(目前很容易超过 50 个不同的请求)。为了尽可能抽象请求的创建,我们添加了一个名为 TRequestMessageParser 的抽象类来委托(delegate) SOAP 请求的构造。

此抽象类接收参数列表,并具有一个 SetParameterValues 方法,用于使用新的 RTTI 填充相应的 SOAP 请求。它创建并填充给定请求的对象参数、数组参数和其他复杂结构。然后,我们创建与 WSDL 导入器 生成的特定请求类型 绑定(bind)的派生类。这些派生类只做两件事:

  1. 实例化请求。
  2. 调用SetParameterValues

现在,这工作正常(或者看起来)。请求已创建,如果您对其进行调试,您可以看到参数中指定的所有属性均已设置,无论它们是序数类型、实例还是动态数组。

当请求被解析为 XML 文本 时,问题就出现了。发生这种情况时,动态数组属性永远不会设置。我们可以通过使用我们分配给服务包装器的 THTTPRIOOnBeforeExecute 事件处理程序来确认这一点。不会引发错误或异常。动态数组属性将被简单地忽略。

如果我们手动创建请求,即具体创建和设置每个对象、数组和属性,则请求(看起来与 RTTI 相同)将被正确解析为 XML 文本。

很明显,当我们使用 RTTI 创建请求时,我们一定做错了什么,尽管尽管进行了调试和谷歌搜索转换错误,但我们找不到它是什么。

下面是TRequestMessageParser类的相关代码:

TRequestMessageParser<REQ: TRemotable> = class
protected
FRequest : REQ;
<snip rest of declaration>

procedure TRequestMessageParser<REQ>.SetParameterValues(Parameters: TObjectList<TRequestParameter>);
begin
SetParameterValues(FRequest, Parameters);
end;

procedure TRequestMessageParser<REQ>.SetParameterValues(parentObject: TObject; ParameterList : TObjectList<TRequestParameter>);
var
parameter : TRequestParameter;
requestPropertyRttiType : TRttiType;
requestProperty : TRttiProperty;
booleanValue : boolean;
begin
//context is initialized in constructor
for parameter in ParameterList do
begin

if parameter.IsComplexType then //true if it has > 1 subparameter (object or array)
begin
requestProperty := context.GetType(parentObject.ClassType).GetProperty(parameter.Code);
requestPropertyRttiType := requestProperty.PropertyType;

case requestPropertyRttiType.TypeKind of
tkClass: ManageObjectProperty(parentObject, requestPropertyRttiType, parameter);
tkDynArray: ManageDynamicArrayProperty(parentObject, parameter);
else
raise Exception.Create('Unsupported type for requests.');
end;
end
else
//ordinal types
begin
requestProperty := context.GetType(parentObject.ClassType).GetProperty(parameter.Code);

if requestProperty.PropertyType.TypeKind = tkEnumeration then
begin
if (requestProperty.PropertyType as TRttiEnumerationType).UnderlyingType.Handle = System.TypeInfo(Boolean) then
begin
booleanValue := parameter.Value;
requestProperty.SetValue(parentObject, TValue.From(booleanValue));
end
//TODO: probably not necessary as SOAP request have no enumerations so far
else
requestProperty.SetValue(parentObject, TValue.FromVariant(parameter.Value));
end
else
requestProperty.SetValue(parentObject, TValue.FromVariant(parameter.Value));
end;
end;
end;


procedure TRequestMessageParser<REQ>.ManageObjectProperty(parentObject: TObject; requestPropertyRttiType : TRttiType; parameter : TRequestParameter);
var
requestPropertyInstance : TObject;
requestProperty : TRttiProperty;
begin
requestPropertyInstance := requestPropertyRttiType.AsInstance.MetaclassType.Create;

//we add the instance to the parent object
requestProperty := context.GetType(parentObject.ClassType).GetProperty(parameter.Code);
requestProperty.SetValue(parentObject, requestPropertyInstance);

//we assign the parameters corresponding to the instance
SetParameterValues(requestPropertyInstance, parameter.Subparameters);
end;


procedure TRequestMessageParser<REQ>.ManageDynamicArrayProperty(parentObject: TObject; parameter : TRequestParameter);
var
parentType : trttiType;
objectProperty : TRttiProperty;
DynArrayType: TRttiDynamicArrayType;
DynArrElementType: TRttiType;
newArrayValue : TValue;
parentObjectArrayValue : TValue;
ArrayLength : LongInt;
i : integer;
begin
//we retrive rtti information for the property
parentType := context.GetType(parentObject.ClassInfo);
objectProperty := parentType.GetProperty(parameter.Code);
DynArrayType := (objectProperty.PropertyType as TRttiDynamicArrayType);

//we retrieve a reference to the property as TValue
newArrayValue := objectProperty.GetValue(parentObject);

//we get and set the dynamic array length
arrayLength := parameter.Subparameters.Count;
DynArraySetLength(PPointer(newArrayValue.GetReferenceToRawData)^, newArrayValue.TypeInfo, 1, @arrayLength);

//we retrieve the array element type
DynArrElementType := DynArrayType.ElementType;

//if it is an object we create the corresponding instances
if DynArrElementType.IsInstance then
begin
for i := 0 to ArrayLength - 1 do
AddObjectElementToDynamicArray(newArrayValue, i, DynArrElementType, parameter.Subparameters[i]);
end
//if it is an ordinal element we assign the value
else if DynArrElementType.IsOrdinal then
begin
for i := 0 to ArrayLength - 1 do
newArrayValue.SetArrayElement(i, TValue.FromVariant(parameter.Subparameters[i].Value));
end
else
raise Exception.Create('Unsupported');


//until now we have a copy of the dynamic array so we reassign it to the property
TValue.MakeWithoutCopy(newArrayValue.GetReferenceToRawData, DynArrayType.Handle, parentObjectArrayValue);
objectProperty.SetValue(parentObject, parentObjectArrayValue);
end;


procedure TRequestMessageParser<REQ>.AddObjectElementToDynamicArray(DynamicArray : TValue; position: integer; DynamicArrayElementType: TRttiType; objectElementParameter: TRequestParameter);
var
ElementValue : TValue;
objectSubparameter : TRequestParameter;
begin
ElementValue := DynamicArrayElementType.GetMethod('Create').Invoke(DynamicArrayElementType.AsInstance.MetaclassType, []);

SetParameterValues(ElementValue.AsObject, objectElementParameter.Subparameters);
DynamicArray.SetArrayElement(position, ElementValue);
end;

TRequestParameter 是一个简单的类,它包含一个 Code、一个 Value 和一个子参数列表(通用的 TObjectList),所有这些都可以通过 read 属性访问。如果您需要查看它,我也可以添加它的代码。

我们使用 Delphi XE5 来创建应用程序。如果有人至少能告诉我们我们做错了什么,那就太好了!

最佳答案

正如 @J... 所暗示的问题是(不知何故)动态数组在发送请求时超出了范围。

为了解决这个问题,我们在创建请求之后但在将其发送到服务之前为请求的每个动态数组属性分配相同动态数组的副本。复制是在发送请求之前完成的,如下所示:

Foo := TFooRequestMessageParser.getRequest;
//for each dynamic array property get a copy. This applies also to subproperties
Foo.DynArrayProperty := Copy(Foo.DynArrayProperty);
fooService.SendRequest(foo);

另一种可能性是像@J...也建议的那样,即手动增加引用计数以避免动态数组被释放。这可能是一种更明智、更快捷的实现方式,但目前我们将坚持我们的解决方案。

关于delphi - 使用 RTTI 创建的 SOAP 请求未完全解析为 XML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23498070/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com