DataSnap 2009 系列之二 (方法篇)

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介: (方法篇)    在过去客户端要调用远程服务器的方法需要通过在TLB里添加接口并且在服务器对象中实现,在DataSnap 2009中调用远程服务器的方法是基于delphi的RTTI机制的,想要一个类允许被远程调用需要做以下两点:    1.

(方法篇)

    在过去客户端要调用远程服务器的方法需要通过在TLB里添加接口并且在服务器对象中实现,在DataSnap 2009中调用远程服务器的方法是基于delphi的RTTI机制的,想要一个类允许被远程调用需要做以下两点:

    1.把该类和DSServerClass连接在一起

    注意:DSServerClass必须设置要导出的类 否则会出现SOnGetClassNotSet的异常信息

    2.该类必须使用$MethodInfo编译指令生成详细的RTTI信息

    所以我们使用向导添加的ServerModule 不需要再手动添加$MethodInfo开关,同样我们也可以不用继承自 TDSServerModule来实现我们的ServerClass,只要从TPersistent继承一个类 并且用{$MethodInfo ON}和{$MethodInfo OFF}包围就可以输出成员函数到客户端。

  注意:要输出的成员函数必须声明为public

  客户端调用可以使用两种方法:

  1.使用SqlServerMethod组件

  通过设置其ServerMethodName属性来进行远程调用 使用Params属性来传递参数和结果值

  2.使用本地代理类

  选中SQLConnection组件,在右键菜单中单击Generate Datasnap client classe 生成代理类单元。

    下面我们通过一个简单的DEMO来展示DataSnap 2009的远程方法调用,我们在服务端定义了4个输出的成员函数:

TSM = class(TDSServerModule) public   function Hello(Message: String): String;   function VariantMethod(Value: OleVariant): OleVariant;   function StreamMethod: TStream;   function VarOutMethod(out OutParam: OleVariant; var VarParam: OleVariant): string; end;

由于在DataSnap内部是使用TDBXValue来管理参数列表的,所以使用string等delphi语言自带的类型将会进行相应的映射。使用TDBXValue也是效率最高的,以下是可以作为参数使用的TDBXValue列表。

TDBXWideStringValue
TDBXAnsiStringValue
TDBXInt16Value
TDBXInt32Value
TDBXInt64Value
TDBXSingleValue
TDBXDoubleValue
TDBXBcdValue
TDBXTimeValue
TDBXDateValue
TDBXTimeStampValue
TDBXBooleanValue
TDBXReaderValue
TDBXStreamValue

我们分别使用SqlServerMethod和代理类完成对服务端Hello方法的调用

SqlServerMethod.ServerMethodName := 'TSM.Hello'; SqlServerMethod.Params[0].AsString := Name.Text; SqlServerMethod.ExecuteMethod; Memo.Lines.Add('Use SqlServerMethod: ' + SqlServerMethod.Params[1].AsString);

    这里参数使用了索引值进行访问传递的顺序是从左到右添加到Params列表 返回值是在列表的最后一个位置,同样也可以使用 ParamByName(参数名称).Value的形式传递参数 返回值的名称默认是'ReturnParameter'。使用代理类调用的方法和调用本地方法区别不大 因为远程调用的具体过程已经被代理类封装可以看下代理类中生成的Hello方法。

function TSMClient.Hello(Message: string): string; begin   if FHelloCommand = nil then   begin     FHelloCommand := FDBXConnection.CreateCommand;     FHelloCommand.CommandType := TDBXCommandTypes.DSServerMethod;     FHelloCommand.Text := 'TSM.Hello';     FHelloCommand.Prepare;   end;   FHelloCommand.Parameters[0].Value.SetWideString(Message);   FHelloCommand.ExecuteUpdate;   Result := FHelloCommand.Parameters[1].Value.GetWideString; end;

  我们看到代理类使用了比SqlServerMethod更低级的DBXCommand进行了封装 以更友好的方式给我们使用

with TSMClient.Create(SQLConnection.DBXConnection) do begin   Memo.Lines.Add('Use Proxy: ' + Hello(Name.Text));   Free; end;

  下面我们用TStream返回一个结构体并且在客户端读出

  服务端部分

TName = packed record   FirstName: array[0..99] of Char;   LastName: array[0..99] of Char; end; function TSM.StreamMethod: TStream; var   Name: TName; begin   Name.FirstName := '爱新觉罗';   Name.LastName := '玄烨';   Result := TMemoryStream.Create;   Result.Seek(0, soFromBeginning);   Result.Write(Name, SizeOf(TName));   Result.Seek(0, soFromBeginning); //返回到客户端的数据是从position开始的 end;

  注意:写完数据以后需要定位到头部 否则客户端得到的数据长度为0

客户端部分

procedure TMainForm.StreamTestClick(Sender: TObject); var   Name: TName; begin   if SQLConnection.Connected  then   begin     with TSMClient.Create(SQLConnection.DBXConnection) do     begin       StreamMethod.ReadBuffer(Name, SizeOf(TName));       Memo.Lines.Add(Format('(StreamMethod)FirstName: %s LastName: %s',[Name.FirstName, Name.LastName]));       Free;     end;   end; end;

  最后一个函数演示了使用var和out关键字来返回参数,以下是可以使用这两个关键字的标量值类型:

boolean
SmallInt
Integer
Int64
Single
Double
AnsiString
String
TDBXTime
TDBXDate

  再加上其他的参数类型

TStream
TDataSet
TParams
TDBXReader
TDBXConnection

  但是在实际测试过程中发现在使用string类型做out和var的参数时 无法使用,跟踪发现源码中ansistring和 string的相关代码已经被注释掉 估计是有BUG存在所以不支持 以后应该可以修复。

  以下摘自DSReflect单元的 procedure TDSMethodValues.AssignParameterValues(Parameters: TDBXParameterArray);

//        TDBXDataTypes.AnsiStringType: //        begin //          s := Value.GetAnsiString; //          GetMem(p, SizeOf(Pointer)); //          UniqueString(s); //          PPointer(p)^ := Pointer(s); //          FMethodValues[i] := MakeRefVar(varString, p); //        end; //        TDBXDataTypes.BytesType: //        begin //          SetLength(bytes, value.GetValueSize); //          Value.GetBytes(0, bytes, 0, Length(Bytes)); //          GetMem(p, Length(bytes)); //          Move(bytes[0], p^, Length(bytes)); //          FMethodValues[i] := MakeRefVar(varByte or varArray, p); //        end; //        TDBXDataTypes.WideStringType: //        begin //          w := Value.GetWideString; //          GetMem(p, SizeOf(Pointer)); //          UniqueString(w); //          PPointer(p)^ := Pointer(w); //          FMethodValues[i] := MakeRefVar(varUString, p); //        end;

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
缓存 安全 iOS开发
iOS网络编程之四——请求类NSURLRequest使用详解
iOS网络编程之四——请求类NSURLRequest使用详解
467 0
WCF技术剖析之三十:一个很有用的WCF调用编程技巧[上篇]
原文:WCF技术剖析之三十:一个很有用的WCF调用编程技巧[上篇] 在进行基于会话信道的WCF服务调用中,由于受到并发信道数量的限制,我们需要及时的关闭信道;当遇到某些异常,我们需要强行中止(Abort)信道,相关的原理,可以参考我的文章《服务代理不能得到及时关闭会有什么后果?》。
883 0
|
缓存
WCF技术剖析之三十:一个很有用的WCF调用编程技巧[下篇]
原文:WCF技术剖析之三十:一个很有用的WCF调用编程技巧[下篇] 在《上篇》中,我通过使用Delegate的方式解决了服务调用过程中的异常处理以及对服务代理的关闭。对于《WCF技术剖析(卷1)》的读者,应该会知道在第7章中我通过类似于AOP的方式解决了相似的问题,现在我们来讨论这个解决方案。
964 0