我过去使用Delphi制作了Web服务,但大多数都很简单,只需要一些参数并将一个值返回给客户端。我正在努力的一项新服务要求我能够发送和接收复杂类型。请考虑在我的代码中定义以下类型:
TBaseRequest = Class(TRemotable)
private
FUsername: string;
FPassword: string;
published
Property Username: String read FUsername write FUsername;
Property Password: String read FPassword write FPassword;
End;
TBaseResponse = Class(TRemotable)
private
FStatusMessage: string;
FStatusCode: integer;
published
Property StatusMessage: string read FStatusMessage write FStatusMessage;
Property StatusCode: integer read FStatusCode write FStatusCode;
End;
TSepecialRequest = class(TBaseRequest)
private
FExtraParam: string;
published
Property ExtraParam: String read FExtraParam write FExtraParam;
end;
TSpecialResponse = class(TBaseResponse)
private
FExtraResult: string;
published
Property ExtraResult: String read FExtraResultwrite FExtraResult;
end;
所有这些类都使用RemClassRegistry.RegisterXSClass注册。
现在我还在这个webservice的界面中定义了以下函数:
function SpecialMethod(request:TSepecialRequest): TSpecialResponse;
在服务代码中,我可以轻松访问父类属性,如Username和Password,但是如果我们查看生成的WSDL,我们会看到TSpecialRequest和TSpecialResponse类成员包含在架构部分中。
<xs:complexType name="TSpecialRequest">
<xs:complexContent>
<xs:extension base="TBaseRequest">
<xs:sequence>
<xs:element name="ExtraParam" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="TSpecialResponse">
<xs:complexContent>
<xs:extension base="TBaseResponse">
<xs:sequence>
<xs:element name="ExtraResult" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
WSDL中的这个模式片段显示TSpecials是TBase类的扩展,并且一切都很好,除了TBase类的描述不包含在模式中。我希望也有这样的部分,但它缺少:
<xs:complexType name="TBaseRequest">
<xs:sequence>
<xs:element name="Username" type="xs:string"/>
<xs:element name="Password" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TBaseResponse">
<xs:sequence>
<xs:element name="StatusMessage" type="xs:string"/>
<xs:element name="StatusCode" type="xs:int"/>
</xs:sequence>
</xs:complexType>
但是,生成的WSDL中缺少此架构片段。这意味着任何尝试使用此服务的客户端都无法正确生成请求或解释响应。例如,如果我尝试将生成的WSDL加载到Delphi 2009中的WSDL导入器中,我将获得以下类:
TSpecialRequest = class(TRemotable)
private
FExtraParam: WideString;
published
property ExtraParam: WideString read FExtraParam write FExtraParam;
end;
TSpecialResponse = class(TRemotable)
private
FStatusMessage: WideString;
FStatusCode: Integer;
published
property StatusMessag: WideString read FStatusMessage write FStatusMessage;
property StatusCode: Integer read FStatusCode write FStatusCode;
end;
结果是客户端代码无法执行设置应成为TSpecialRequest一部分的用户名和密码成员的事情。
有没有人知道为什么会发生这种情况或我能做些什么呢?
答案 0 :(得分:1)
我认为我不会得到答案,但我找到了解决方法。我对此并不满意,但它让我解决了问题。通过使用对象组合而不是继承,可以避免上述症状。此代码按预期运行,但使用起来不太简单。我想我会在我的实现中提出某种消息工厂,但那就是主题。
此解决方案可通过以下代码说明:
TBaseRequest = Class(TRemotable)
private
FUsername: string;
FPassword: string;
published
Property Username: String read FUsername write FUsername;
Property Password: String read FPassword write FPassword;
end;
TSepecialRequest = class(TRemotable)
private
FExtraParam: string;
FBaseRequest: TBaseRequest;
published
Property ExtraParam: String read FExtraParam write FExtraParam;
Property BaseRequest: TBaseRequest read FBaseRequest write FBaseRequest;
end;
答案 1 :(得分:1)
Delphi仅为在Web服务的界面中直接引用的类生成模式。理想情况下,它应该包含返回TRemotable的基类,但它不包括。
我发现,如果你在参数列表中使用基类添加一个虚拟方法,Delphi将生成缺少的定义。例如:
procedure BaseClasses(BaseRequest: TBaseRequest; BaseResponse: TBaseResponse); stdcall;
这绝对是一个黑客攻击而且必须公开这样的方法有点烦人,但它确实完成了你想做的事。
我知道这个回复对你来说有点晚了,但也许这对其他人来说很有用。