RO11 -
用
RemObjects SDK
创建异步调用客户端
RemObjects SDK (
简称
RO)
提供了创建异步客户端的功能
.
这个文档快速的介绍一下什么是异步客户端
,
如何通过
RO
执行
.
为什么使用异步调用
?
通常当你的
RO
客户端程序向服务器端请求调用时
,
客户端执行过程会等待请求调用返回
,
这时请求传递给服务器
,
在服务器上处理
,
调用结果从服务器上返回
.
对于服务类型和请求的方法
,
用可能要等上几秒或更长时间
.
也就是说当你在
LAN
或
Internet
上调用服务时可能会让客户明确的感觉到延时
,
应用程序看上去像死掉了一样
.
而且当处理过程超过几秒时
,
只向用户显示一个漏斗光标是不够的
,
客户可能会希望在服务器执行的过程中继续做其它的操作
.
异步调用正是让你完整这个功能
-
当服务器端处理请求时你的应用程序还是可响应的
.
这是怎么完成的呢
?
在创建异步客户端时
,
所有向服务器请求的调用都分为独立的两个方法
:
一个提供所有的输入参数
(var
和
Const)
调用后立即返回
,
另一个返回所有的输出参数
(Var,out
和
Result).
加入有一个在服务器端执行的接口
,
其中的
Calc
方法执行要花费很长时间
(
如
30
分钟
):
type
IComplexCalculation = interface
function Calc(const iValueA, iValueB:integer; var ioValueC:integer):string;
end;
可见
Calc
函数有
3
个输入参数和
2
个输出
(ioValueC
和返回值
).
当在客户端异步调用时
,
接口对客户端而言应如下所示
:
type
IComplexCalculation_Async = interface(IROAsync)
procedure Invoke_Calc(const iValueA, iValueB, ioValueC:integer);
function Receive_Calc(out ioValueC:integer):string;
end;
注意新的接口如何产生两个变体的
Calc
方法
.
首先
, Invoke_Calc
传入的都是输入参数
,
另外一个
Receive_Calc
只返回输出部分
.
在客户端编码时你也要向其它
RO
客户端一样生产服务对象的代理
.
用户调用
Invoke_Calc
触发服务器端的计算
.
不象原来的
Calc
方法
,Invoke_Calc
方法马上返回
,
用户可以继续使用应用程序
.
当服务器端执行完调用返回计算结果时
,
你可以调用
Receive_Calc
方法获取返回值并将之反馈给用户
.
在等待调用结果时
,
你的应用程序定时查看
AnswerReceived
属性
(
在
IROAsync
接口中定义
)
判断调用是否完成
,
并可能相应的更新状态栏或菜单栏工具栏
.
使用
SDK
写一个异步客户端
现在你已经明白在特定情况下使用异步客户端的好处了
,
下面让我们看看使用
RO
提供的功能轻松创建异步客户端
..
首先
,
异步调用完全在客户端
,
这意味着你可以使用他们去调用任意几经存在的
RO
服务
,
而不用去改变从编译部署服务
.
第一部创建你要调用的服务的异步调用接口
.RO
提供了多种方法从
RODL
创建异步接口
.
最简单的方法是使用
IDE.
在
IDE
主菜单调用
RemObjects SDK | Regenerate Async unit
将在服务项目中生产新的异步调用单元
.
另外可以使用
Service Builder
的菜单项
CodeGen/Delphi/Async Interface:
第三种方式是使用
RODL.exe
实用程序从
RODL
文件生成代码
,
你可以用这种方式对任意的
RODL
文件生成
*_Async.pas
文件
.
不用担心你只有服务的
WSDL
文件
,
如你希望异步调用存在的
Soap web service,
你只要简单的将
WSDl
文件导入的
ServiceBuilder
中并保持为
RODL
文件即可
.
使用命令行从
RODL
中生成异步接口单元
,
使用如下命令
:
RODL /rodl:<path-to/rodl> /language:pascal /type:async
之后你将在
RODL
文件同目录下找到生成的
_Async.pas
文件
.
将之添加到你的客户端项目中一切
OK.
在你的应用程序中有两个按钮
,
一个是
"Invoke Calculation"
另一个是
"Show Result".
将第二个按钮的
Enabled
属性设置为
False.
在第一个按钮的事件处理中创建代理对象
(
与其它
RO
客户端一样的方式
),
将之保存为全局变量
(
窗体成员
)
并调用其函数
:
procedure
btn_InvokeClick(...)
begin
fProxy := CoCalcServer_Async.Create(BinMessage1, HttpChannel1);
fProxy.Invoke_Calc(...);
btn_Invoke.Enabled := false;
end
;
第二个按钮事件处理函数中简单的调用
Receive_Calc
函数并向用户展示返回的结果
:
procedure
btn_ReceiveClick(...)
begin
ShowMessage(Receive_Calc(...));
fProxy := nil;
btn_Invoke.Enabled := true;
btn_Receive.Enabled := false;
end
;
最后增加一个
Timer
控件定时检查调用是否返回并将第二个按钮
Enabeld
属性设为
True.
设置
TTimer
的
Interval
为
1000
并完成其事件处理函数
:
procedure
timer_CheckTimer(...)
begin
btn_Receive.Enabled := Assigned(fProxy) and fProxy.AnswerReceived;
end
;
现在启动你的程序只有
Invoke
按钮可用
,
一旦你点击它
,
它将不可用
,
应用程序将等待服务器的返回结果
.
注意现在你的用户接口是可以响应的
,
用户可以继续操作
.
当请求结果返回时
Show Result
按钮可用
,
用户点击查看结果
.
后台
异步调用在后台是如何执行的呢
.
首先
,
异步调用完全在客户端
.
这意味着在客户端
,
异步调用被发送到服务器端
,
并等待服务器端相应
.
为了不阻塞线程
(VCLGUI
线程或其它线程
),
异步代理创建一个后台工作线程处理与服务器的通信
.
代理序列化原始消息
(
调用方法的基本信息和所有输入参数
)
后传递给后台线程
,
接下来马上返回
.
这个后台线程建立一个与服务器的连接
,
发送调用消息并等待响应
.
一旦它收到响应消息
,
马上传递给代理对象
,
后台线程结束
.
客户端应用程序调用
Receive_Calc
方法得到返回值
(
或其它信息
).