程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> DataSnap 2009 系列之二 (方法篇)

DataSnap 2009 系列之二 (方法篇)

編輯:Delphi

 本文示例源代碼或素材下載

   在過去客戶端要調用遠程服務器的方法需要通過在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;

DataSnap 2009 系列之二 (方法篇)

  圖片看不清楚?請點擊這裡查看原圖(大圖)。  



  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved