DataSnap 2009 系列之二 (方法篇)

(方法篇)

    在过去客户端要调用远程服务器的方法需要通过在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;

时间: 2024-10-31 23:04:37

DataSnap 2009 系列之二 (方法篇)的相关文章

DataSnap 2009 系列之三 (生命周期篇)

(生命周期篇) DataSnap 2009的服务器对象的生命周期依赖于DSServerClass组件的设置,当DSServer启动时从 DSServerClass组件读取LifeCycle属性的值. 注意:LifeCycle的值由于在启动时就已经读取 启动后再修改LifeCycle的值将没有任何效果,LifeCycle属性的值可以是以下三种字符串之一. 1.Session 该选项为默认设置,每个连接都会建立一个独立的服务器对象为客户端提供服务,服务器对象在连接关闭后释放,因此多个客户端访问的是不

DataSnap 2009 系列之一 (系统连接篇)

(连接篇) Delphi 的MIDAS出来了这么多年终于有改进的版本了,COM-FREE的DataSnap 2009真是清爽了很多,DataSnap 2009 除了不支持回调和Intercept组件以外 其它的该有的都有了 而且还有很多强大的特性: 第一篇就先写点DataSnap 2009连接方面可能要用到的东西,以后再继续写写关于生命周期的管理 对象池的应用 以及远程管理 远程方法调用等方面的东西吧. 首先 建立个DataSnap 2009的服务器工程,一共用到三个组件:    DSServe

盘点2009系列之二:这一年赚钱风声特别多

房价攀升.创业板造富.大蒜泡沫.汽车疯狂--2009年,"赚钱风声"刺激国人. <中国经济周刊>记者 谈佳隆/综合报道 1. 股指重上3000点 上证指数从年初1800多点,仅用6个月就重新站上了3000点关口.虽然下半年上证指数曾出现反复,并两度跌破3000点,但此后又顽强回到3000点上.时至年末,此一关口依然成为重要的技术和心理支撑.股市向好给广大股民带来了赚钱效应.据相关调查,61.3%的散户在今年炒股赚了钱,其中,有约6.2%的散户年赢利在一倍以上. 点评:中国证

Docker容器互联方法--篇二

本文讲的是Docker容器互联方法--篇二,[编者的话]本文为Eddy Mavungu博士于DEIS官方博客中发布的系列文章的第二部分,Eddy博士在本篇系列文章中分享了Docker容器间互联的方法,并且做了演示.Eddy博士是DEIS公司的创始人,同时也是一位高级研究顾问.本文根据他于DEIS官方博客上发布的文章翻译而成. 这篇系列文章的第二部分会看一下如何连接Docker各容器. 我们在第一节谈及了Docker的bridge接口,它可以让我们连接所有在相同Docker宿主机上的容器.特别需要

深入浅出Mybatis系列(二)---配置简介(mybatis源码篇)

深入浅出Mybatis系列(二)---配置简介(mybatis源码篇) 上篇文章<深入浅出Mybatis系列(一)---Mybatis入门>, 写了一个Demo简单体现了一下Mybatis的流程.本次,将简单介绍一下Mybatis的配置文件: 上次例子中,我们以 SqlSessionFactoryBuilder 去创建 SqlSessionFactory,  那么,我们就先从SqlSessionFactoryBuilder入手, 咱们先看看源码是怎么实现的: SqlSessionFactory

ASP.net控件开发系列之二

"生死有序" "装装孙子" 上篇文章<开篇>说了不少空洞的理论,这篇文章我还是先说说"大而化之"的东西:1.ASP.net控件(包括页面本身)的生命期的细节:2.如何开始一个控件的编写. "生死有序" ASP.net处理程序在接收到一个用户的页面请求后,它是如何变戏法把一个鲜活的页面呈现给客户端的呢?它都做了哪些事?按什么顺序做的? 要说明这个问题,我们首先要明白,一个页面它本身也是一个Control.从设计模式的

[算法系列之二十四]后缀树(Suffix Tree)

之前有篇文章([算法系列之二十]字典树(Trie))我们详细的介绍了字典树.有了这些基础我们就能更好的理解后缀树了. 一 引言 模式匹配问题 给定一个文本text[0-n-1], 和一个模式串 pattern[0-m-1],写一个函数 search(char pattern[], char text[]), 打印出pattern在text中出现的所有位置(n > m). 这个问题已经有两个经典的算法:KMP算法 ,有限自动机,前者是对模式串pattern做预处理,后者是对待查证文本text做预处

UWP开发砸手机系列(二)—— “讲述人”识别自定义控件Command

原文:UWP开发砸手机系列(二)-- "讲述人"识别自定义控件Command 上一篇我们提到如何让"讲述人"读出自定义的CanReadGrid,但"讲述人"仍然无法识别CanReadGrid上绑定的Command.XAML代码如下: <StackPanel> <TextBlock Text="{x:Bind Title,Mode=OneWay}" Foreground="White">

LXD 2.0系列之二:LXD安装和配置

本文讲的是LXD 2.0系列之二:LXD安装和配置,[编者的话]第三方调查报告显示LXD有潜质成为一款受欢迎的第三方容器管理工具.本文是LXD核心维护者.加拿大程序员Stéphane Graber有关LXD连载博文的第二篇. [LXD 2.0系列开篇:是时候讨论LXD的一切了][LXD 2.0系列之一:LXD简介][LXD 2.0系列之二:LXD安装和配置][LXD 2.0系列之三:你的第一个LXD容器][LXD 2.0系列之四:资源管理][LXD 2.0系列之五:镜像管理][LXD 2.0系列