DataSnap 2009 系列之二 (方法篇)
在過去客戶端要調(diào)用遠(yuǎn)程服務(wù)器的方法需要通過在TLB里添加接口并且在服務(wù)器對象中實現(xiàn)
在DataSnap 2009中調(diào)用遠(yuǎn)程服務(wù)器的方法是基于delphi的RTTI機(jī)制的
想要一個類允許被遠(yuǎn)程調(diào)用需要做以下兩點
1.把該類和DSServerClass連接在一起
procedure TMainForm.DSServerClassGetClass(DSServerClass: TDSServerClass;var PersistentClass: TPersistentClass);
begin
PersistentClass := TSM;
end;
DSServerClass的OnGetClass就是用于完成此任務(wù)的
注意:DSServerClass必須設(shè)置要導(dǎo)出的類 否則會出現(xiàn)SOnGetClassNotSet的異常信息
2.該類必須使用$MethodInfo編譯指令生成詳細(xì)的RTTI信息
{$MethodInfo ON}TDSServerModule = class(TProviderDataModule)
end;
{$MethodInfo OFF}
我們查看TDSServerModule的定義發(fā)現(xiàn)已經(jīng)完成了該步驟
所以我們使用向?qū)砑拥腟erverModule 不需要再手動添加$MethodInfo開關(guān)
同樣我們也可以不用繼承自TDSServerModule來實現(xiàn)我們的ServerClass
只要從TPersistent繼承一個類 并且用{$MethodInfo ON}和{$MethodInfo OFF}包圍就可以輸出成員函數(shù)到客戶端
注意:要輸出的成員函數(shù)必須聲明為public
客戶端調(diào)用可以使用兩種方法
1.使用SqlServerMethod組件
通過設(shè)置其ServerMethodName屬性來進(jìn)行遠(yuǎn)程調(diào)用 使用Params屬性來傳遞參數(shù)和結(jié)果值
2.使用本地代理類
選中SQLConnection組件,在右鍵菜單中單擊Generate Datasnap client classe 生成代理類單元。
下面我們通過一個簡單的DEMO來展示DataSnap 2009的遠(yuǎn)程方法調(diào)用
我們在服務(wù)端定義了4個輸出的成員函數(shù)
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內(nèi)部是使用TDBXValue來管理參數(shù)列表的
所以使用string等delphi語言自帶的類型將會進(jìn)行相應(yīng)的映射
使用TDBXValue也是效率最高的
以下是可以作為參數(shù)使用的TDBXValue列表
TDBXWideStringValue
TDBXAnsiStringValue
TDBXInt16Value
TDBXInt32Value
TDBXInt64Value
TDBXSingleValue
TDBXDoubleValue
TDBXBcdValue
TDBXTimeValue
TDBXDateValue
TDBXTimeStampValue
TDBXBooleanValue
TDBXReaderValue
TDBXStreamValue
我們分別使用SqlServerMethod和代理類完成對服務(wù)端Hello方法的調(diào)用
SqlServerMethod.ServerMethodName := 'TSM.Hello';SqlServerMethod.Params[0].AsString := Name.Text;
SqlServerMethod.ExecuteMethod;
Memo.Lines.Add('Use SqlServerMethod: ' + SqlServerMethod.Params[1].AsString);
這里參數(shù)使用了索引值進(jìn)行訪問 傳遞的順序是從左到右添加到Params列表 返回值是在列表的最后一個位置
同樣也可以使用ParamByName(參數(shù)名稱).Value的形式傳遞參數(shù) 返回值的名稱默認(rèn)是'ReturnParameter'
使用代理類調(diào)用的方法和調(diào)用本地方法區(qū)別不大 因為遠(yuǎn)程調(diào)用的具體過程已經(jīng)被代理類封裝
可以看下代理類中生成的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進(jìn)行了封裝 以更友好的方式給我們使用
begin
Memo.Lines.Add('Use Proxy: ' + Hello(Name.Text));
Free;
end;
下面我們用TStream返回一個結(jié)構(gòu)體并且在客戶端讀出
服務(wù)端部分
TName = packed recordFirstName: 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); //返回到客戶端的數(shù)據(jù)是從position開始的
end;
注意:寫完數(shù)據(jù)以后需要定位到頭部 否則客戶端得到的數(shù)據(jù)長度為0
客戶端部分
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;
最后一個函數(shù)演示了使用var和out關(guān)鍵字來返回參數(shù)
以下是可以使用這兩個關(guān)鍵字的標(biāo)量值類型
boolean
SmallInt
Integer
Int64
Single
Double
AnsiString
String
TDBXTime
TDBXDate
再加上其他的參數(shù)類型
TStream
TDataSet
TParams
TDBXReader
TDBXConnection
但是在實際測試過程中發(fā)現(xiàn)在使用string類型做out和var的參數(shù)時 無法使用
跟蹤發(fā)現(xiàn)源碼中ansistring和string的相關(guān)代碼已經(jīng)被注釋掉 估計是有BUG存在所以不支持 以后應(yīng)該可以修復(fù)
以下摘自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
轉(zhuǎn)載于:https://www.cnblogs.com/MaxWoods/archive/2011/09/23/2187839.html
總結(jié)
以上是生活随笔為你收集整理的DataSnap 2009 系列之二 (方法篇)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 复合文档格式研究
- 下一篇: 使用Dockerfile制作镜像