本文示例源代碼或素材下載
在過去客戶端要調用遠程服務器的方法需要通過在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;
圖片看不清楚?請點擊這裡查看原圖(大圖)。