• DataSnap 2009 系列之二 (方法篇)


    在过去客户端要调用远程服务器的方法需要通过在TLB里添加接口并且在服务器对象中实现

    在DataSnap 2009中调用远程服务器的方法是基于delphi的RTTI机制的

    想要一个类允许被远程调用需要做以下两点

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

    procedure TMainForm.DSServerClassGetClass(DSServerClass: TDSServerClass;
    var PersistentClass: TPersistentClass);
    begin
    PersistentClass :
    = TSM;
    end;

    DSServerClass的OnGetClass就是用于完成此任务的

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

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

    {$MethodInfo ON}
    TDSServerModule
    = class(TProviderDataModule)
    end;
    {$MethodInfo OFF}

    我们查看TDSServerModule的定义发现已经完成了该步骤

    所以我们使用向导添加的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;

    贴上效果图


    附上DEMO源码 DataSnapDemo_2.rar

  • 相关阅读:
    ElasticSearch7.3学习(十九) deep paging
    vuerouter 学习
    vuerouter学习 Login.vue
    背包问题贪心算法求解
    文件IO基础知识
    mysql 导出索引
    PRFAQAWS 断舍离
    LIMS业务流程图
    VM运行centos网络配置(出现错误)详解
    vue keepalive情况下切换页面的tab并改变宽高以后发现echarts内容变成空白
  • 原文地址:https://www.cnblogs.com/MaxWoods/p/2187839.html
Copyright © 2020-2023  润新知