RO09 - RemObjects 2.0 Session 管理器
本文将说明RemObjects SDK 2.0的一个重要特性: Session 管理器.
Sessions
要写一个灵活的服务端首选途径是开发无状态实体. 客户端不保持服务资源(如数据库连接),调用完毕马上释放.
这种方式也用在Web应用程序中,但是出现在CS架构中可以大家就比较陌生了.
SessionServer 范例
SessionServer范例非常简单,但是却展示如何执行常用的功能:授权登陆和只有登陆的用户才能成功调用开放的方法.
这里提供两个服务: LoginService 和SessionService.
LoginService服务接口声明如下:
LoginService = interface
['{A8C9C8A2-3988-4E92-8846-6CDE7B35AA1E}']
function Login(const UserID: String; const Password: String): boolean;
procedure Logout(const SessionID: String);
end;
SessionService服务接口声明如下:
SessionService = interface
['{EE96A14F-A446-4194-A1FD-C4F900DFBE62}']
function GetSessionValue(const Name: String): String;
procedure SetSessionValue(const Name: String; const Value: String);
function GetSessionID: String;
end;
客户端首先调用Login方法传递用户ID和密码(本范例要求用户名和密码相等).
在Login之前调用SessionService服务将抛出异常.
最后, 如果客户端5分钟内没有请求服务,Sessin失效,下次请求需要再次登陆.
RemObjects Session 管理器
Session管理器的思想是使用数据快照保存一个服务对象,当用户调用服务器方法时从中获取信息.
为了使用RemObjects Session,服务端对象必须从TRORemoteDataModule继承. TRORemoteDataModule已经在RemObjects SDK 2.0中扩展,增加了两个新的属性: SessionManager 和RequiresSession.
SessionManager 属性
这个属性必须在单例模式(Singleton)下使用,指向SessionManager控件.在SessionManager服务中要将这些控件放在主窗体中.保证他们唯一并已经实例化
现在在SDK中有两种类型的Session 管理器:
TROInMemorySessionManager: 在服务执行程序内存中保存Session信息,速度快,但是不能长期保存.
TROEventSessionManager:自定义Session管理器,允许将特殊的事件提供处理程序,如CreateSession和DeleteSession.具有很好的可配置性,可以保存Session信息.
RequiresSession 属性and DestroySession 方法
每个服务器端方法都是准备好被调用的,RemObjects引擎检查对象是否继承了IROObjectActivation接口,如果是,则在方法调用前都会触发DoActivate方法,调用后触发DoDeactivate方法..
TRORemoteDatamodule 继承了IROObjectActivation, 在DoActivate及DoDeactivate中获取和释放Session.
为了控制Session的获取和释放,需要使用RequiersSessoin属性和DestroySession方法.
RequiresSession属性通知服务端对象是否允许创建新的Session或是否要使用以及存在的Session. 一般在象Login方法中需要新建一个Session,而在其它的调用中只需用使用存在的Session.
而DestroySession则通知服务端对象从Session列表中删除一个Session.
下面是TRORemoteDataModule.DoOnActivate 方法的代码(unit uRORemoteDataModule.pas):
procedure TRORemoteDataModule.DoOnActivate(aClientID: TGUID);
begin
fSession := fSessionManager.FindSession(aClientID);
if (fSession=NIL) then begin
if RequiresSession then
RaiseError(err_SessionNotFound, [GUIDToString(aClientID)])
else
fSession := fSessionManager.CreateSession(aClientID);
end;
end;
从中可见如果RequiresSession为True并且需要的Session没有发现服务端将会抛出异常.
对应的方法执行完毕后将调用 DoDeactivate:
procedure TRORemoteDataModule.DoOnDeactivate(aClientID: TGUID);
begin
[..]
if fDestroySession then
fSessionManager.DeleteSession(fSession.SessionID, FALSE)
else
fSessionManager.ReleaseSession(fSession);
end;
LoginService 编程
你将发现在RemObjects SDK中实现一个Login服务是多么简单.注意LoginService的RequiresSession属性设置为False.
function TLoginService.Login(const UserID: String;
const Password: String): boolean;
begin
result := (UserID=Password);
if not result then DestroySession;
// Informs the SessionManager to discard the session because the login failed
end;
procedure TLoginService.Logout(const SessionID: String);
begin
DestroySession; // Discards the session
end;
SessionService 编程
下面的代码向你展示如何在其它的服务中使用Session. 注意:SessionService的RequiresSession属性设置为True.
function TSessionService.GetSessionValue(const Name: String): String;
begin
result := Session.Values[Name]
end;
procedure TSessionService.SetSessionValue(const Name: String; const Value: String);
begin
Session.Values[Name] := Value
end;
function TSessionService.GetSessionID: String;
begin
result := GUIDToString(ClientID);
end;