2011 年 01 月 的封存

進階DataSnap回叫功能2 – 不同用戶端藉由回叫功能溝通

雖然一個用戶端應用程式可以藉由註冊一個回叫通道並且在回叫通道中註冊多個回叫ID,但另外一個非常實用的回叫功能就是如何讓不同的用戶端能夠藉由回叫來相互溝通。DataSnap XE的回叫功能也支援不同的用戶端藉由回叫機制來相互傳遞任何的資料,在說明如何實作之前,讓我們總結一下DataSnap框架回叫機制可由用戶端註冊變動的部份包含了:

  • 通道名稱
  • 用戶端識別
  • 回叫識別

因此要讓不同的用戶端能夠藉由回叫功能互動,那麼用戶端只要掌握上述的三個變動的即可。例如用戶端1要和用戶端2藉由回叫互動,用戶端1只需要知道用戶端2存在的通道名稱,用戶端2的用戶端識別以及用戶端2的回叫識別,那麼用戶端1就可以回叫用戶端2來傳遞任何資訊了。

現在就讓我們看看如何實作不同用戶端藉由回叫功能相互溝通。

修改DataSnap伺服器

回到範例回叫專案群組,開啟範例DataSnap伺服器的主表單,在主表單上方加入一個TListBox以顯示所有用戶端識別資訊,另外再加入兩個TButton,分別是『列出所有客戶端識別』以及『清除所有客戶端識別』,如下圖所示:

要取得所有連結到DataSnap伺服器的用戶端識別資訊,我們可以呼叫TDSServer元件的GetAllChannelClientId方法,GetAllChannelClientId能夠回傳在一個特定的回叫通道中所有註冊的用戶端識別,它的原型如下:

function GetAllChannelClientId(const ChannelName: String): TList<String>;

我們只需要傳遞特定的回叫通道給GetAllChannelClientId即可從回傳的TList物件中取得所有註冊的用戶端識別,在這個範例中我們只需要傳入DEMOChannel即可。因此『列出所有客戶端識別』按鈕的OnClick事件處理函式實作如下:

procedure TForm17.btnListAllClientIdsClick(Sender: TObject);

var

aIdList : TList<String>;

sId : String;

begin

aIdList := ServerContainer5.DSServer1.GetAllChannelClientId(DEMOChannel);

try

for sId in aIdList do

lbAllClientIds.Items.Add(sId);

finally

aIdList.Free;

end;

end;

現在就可以修改範例DataSnap用戶端應用程式了。

修改DataSnap用戶端應用程式

開啟範例DataSnap用戶端應用程式的主表單,在其中加入兩個TEdit元件以便讓使用者輸入這個用戶端的用戶端識別以及回叫識別,再置入一個『回叫客戶端』按鈕以及一個TMemo元件,當我們在新的TMemo元件中輸入任何資訊時,再點選『回叫客戶端』按鈕就可以把新的TMemo元件中的資訊藉由回叫功能傳遞給另外一個用戶端應用程式。但我們如何指定要回叫那一個用戶端應用程式呢?這就由新加入的兩個TComboBox來指定了,我們可以在這兩個TComboBox中輸入要溝通的另外一個用戶端的用戶端識別以及回叫識別,那麼『回叫客戶端』按鈕的OnClick事件處理函式就可以藉由回叫功能來回叫另外一個用戶端應用程式了,此時範例用戶端應用程式的主表單如下所示:

接下來就解決的問題是一個用戶端應用程式如何能夠回叫另外一個用戶端應用程式呢? 這可以使用TDSAdminClient類別的NotifyCallback方法。TDSAdminClient是位於DSProxy程式單元中的類別,在XE版中因應強化的回叫功能而加入了數個新的方法,其中的NotifyCallback方法可以回叫指定回叫通道中特定用戶端識別以及回叫識別的用戶端,它的原型宣告如下:

function NotifyCallback(ChannelName: string; ClientId: string; CallbackId: string; Msg: TJSONValue; out Response: TJSONValue): Boolean;

NotifyCallback接受數個參數,下面的表格說明了每一個參數的目的:

參數名稱 說明
ChannelName 回叫通道名稱
ClientId 用戶端識別
CallbackId 回叫識別
Msg 傳遞的資訊
Response 被回叫用戶端的回傳資訊

因此我們只需要為每一個用戶端應用程式在註冊時加入一個獨特的用戶端識別,如此一來我們就可以藉由NotifyCallback讓任何兩個用戶端或是多個用戶端相互溝通了。那麼我們如何設定用戶端識別? 還記得我們在用戶端應用程式中使用了TDSClientCallbackChannelManager元件來註冊用戶端的回叫資訊嗎? TDSClientCallbackChannelManager擁有一個ManagerId特性,這個ManagerId特性就可以做為用戶端的識別,因此讓我們修改用戶端中『啟動回叫功能』按鈕的OnClick事件處理函式如下:

001    procedure TfmMainForm.btnStartClick(Sender: TObject);

002    begin

003      SetupTask;

004      AddIdsToComboBox(edtClientId.Text, edtCallbackId.Text);

005      EnableDisableButtons(False, True, True);

006      DemoChannelManager.ManagerId := edtClientId.Text;

007      DemoChannelManager.RegisterCallback(edtCallbackId.Text, TDemoCallback.Create);

008      aIdList.Add(edtCallbackId.Text);

009    end;

在004行我們把使用者於edtClientId元件輸入的用戶端識別加入到cbClientIds中,並且把使用者於edtCallbackId元件輸入的回叫識別加入到cbCallbackIds中:

procedure TfmMainForm.AddIdsToComboBox(aClientId, aCallbackId: String);

begin

cbClientIds.Items.Add(aClientId);

cbCallbackIds.Items.Add(aCallbackId);

end;

接著在006行設定TDSClientCallbackChannelManager元件的ManagerId特性為使用者於edtClientId元件輸入的用戶端識別,最後才於007行呼叫RegisterCallback註冊這個用戶端的回叫資訊。一旦設定了用戶端識別,其他用戶端就可以使用這個用戶端識別來和這個用戶端進行溝通。

完成了上述的修改之後,我們就可以實作主表單中『回叫客戶端』按鈕的OnClick事件處理函式了:

001    procedure TfmMainForm.btnBroadcastToClientClick(Sender: TObject);

002    var

003      LClient: TDSAdminClient;

004      LMessage: TJSONString;

005      LResponse: TJSONValue;

006      LConnection: TDBXConnection;

007    begin

008      LConnection := scnnCallbackServer.DBXConnection;

009      LClient := TDSAdminClient.Create(LConnection, False);

010      try

011        LMessage := TJSONString.Create(Format(‘呼叫通道: %s, 回叫識別: %s, 客戶端識別: %s, 回叫訊息: %s’,

012          [DemoChannelManager.ChannelName, cbCallbackIds.Text, cbClientIds.Text, mmChannelCallbacks.Text]));

013        try

014          LClient.NotifyCallback(DemoChannelManager.ChannelName, cbClientIds.Text, cbCallbackIds.Text, LMessage, LResponse);

015          try

016            if LResponse <> nil then

017              edtResponse.Text := Format(‘客戶端回應: %s’, [LResponse.ToString])

018            else

019              edtResponse.Text := Format(‘客戶端回應: %s’, [‘nil’]);

020          finally

021            LResponse.Free;

022          end;

023        finally

024          LMessage.Free;

025        end;

026      finally

027        LClient.Free;

028      end;

029    end;

首先我們在009行先建立TDSAdminClient物件,在010行建立要傳遞給其他用戶端應用程式的以TJSONString封裝的訊息,接著在014行就藉由NotifyCallback方法呼叫其他的用戶端,請注意我們傳入的資訊,首先參數是回叫通道名稱,這可以從TDSClientCallbackChannelManager元件的 ChannelName特性值取得,第2個參數是用戶端識別,我們傳入主表單中由使用者在TComboBox元件cbClientIds的Text特性值,第3個參數是用戶端回叫識別,我們傳入主表單中由使用者在TComboBox元件cbCallbackIds的Text特性值,第4個參數是這個用戶端要傳遞給其他用戶端的資訊,我們傳入在011行封裝的TJSONString物件LMessage,最後一個參數則必須傳入型態為TJSONValue的物件以接受其他用戶端回傳的執行結果。

現在請編譯並且執行2份不同的範例用戶端應用程式,如下所示:

讓我們在第一個用戶端應用程式輸入其用戶端識別為『客戶端識別1』,其回叫識別為『回叫識別1』,接著在第二個用戶端應用程式中輸入其用戶端識別為『客戶端識別2』,其回叫識別為『回叫識別2』。之後我們如果點選範例DataSnap伺服器中來『列出所有客戶端識別』按鈕和『列出所有回叫識別』按鈕,那麼就可以如上圖左上方看到,範例DataSnap伺服器果然可在DemoChannel這個回叫通道中找到這些資訊。

現在請在用戶端應用程式1中的兩個TComboBox元件輸入『客戶端識別2』和『回叫識別2』讓用戶端應用程式1回叫用戶端應用程式2。同樣的請在請在用戶端應用程式2中的兩個TComboBox元件輸入『客戶端識別1』和『回叫識別1』讓用戶端應用程式1回叫用戶端應用程式1。

之後在用戶端應用程式1中下方的TMemo元件中輸入任何的資訊,並且點選『回叫客戶端』按鈕,那麼我們立刻可以在用戶端應用程式2的上方TMemo元件中看到由用戶端應用程式1中傳遞來的資訊。同樣的,如果我們在用戶端應用程式2中下方的TMemo元件中輸入任何的資訊,並且點選『回叫客戶端』按鈕,那麼我們立刻可以在用戶端應用程式1的上方TMemo元件中看到由用戶端應用程式2中傳遞來的資訊,此時這兩個用戶端應用程式看起來如下所示:

我們可以看到藉由DataSnap的回叫功能,我們果然可以讓不同的用戶端應用程式都藉由回叫通道來溝通並且相互傳遞任何的資訊。此外請注意上圖中兩個用戶端都相互回傳『客戶端回應:true』的訊息,這是因為我們在前面實作用戶端的回叫函式時,用戶端的回叫函式都回傳TJSONTrue物件。由於NotifyCallback可以回傳回叫用戶端的執行結果,因此如果我們希望回叫函式回傳其他型態的資訊,那麼我們可以修改兩個範例用戶端回叫函式如下:

001    function TDemoCallback.Execute(const Arg: TJSONValue): TJSONValue;

002    var

003      sDemoMessage : String;

004    begin

005    //  Result := TJSONTrue.Create;

006      Result := TJSONString.Create(‘成功呼叫客戶端’);

007

008      if (Arg is TJSONString) then

009      begin

010        sDemoMessage := TJSONString(Arg).Value;

011        TThread.Synchronize(nil,

012                            procedure

013                            begin

014                              fmMainForm.mmDemoMessage.Lines.Text := sDemoMessage;

015                            end

016                            );

017      end;

018    end;

019

020    { TDemoCallback2 }

021

022    constructor TDemoCallback2.Create;

023    begin

024

025    end;

026

027    function TDemoCallback2.Execute(const Arg: TJSONValue): TJSONValue;

028    var

029      sDemoMessage : String;

030    begin

031    //  Result := TJSONTrue.Create;

032      Result := TJSONString.Create(‘成功呼叫客戶端’);

033

034      if (Arg is TJSONString) then

035      begin

036        sDemoMessage := TJSONString(Arg).Value;

037        TThread.Synchronize(nil,

038                            procedure

039                            begin

040                              fmMainForm.mmDemoMessage2.Lines.Text := sDemoMessage;

041                            end

042                            );

043      end;

044 end;

在上面的兩個回叫函式中我們修改回傳TJSONString封裝的資訊而不是單純的TJSONTrue物件,這是果然是因為NotifyCallback回傳的型態是TJSONValue,因此任何從TJSONValue類別繼承下來的類別物件都可以做為回叫函式的執行回傳結果。

現在如果我們再次執行兩個用戶端應用程式,那麼就可以看到類似如下的結果:

從上圖中我們可以看到不同的用戶端果然可以藉由回叫函式傳遞任何的資訊回其他的用戶端應用程式。

現在您應該已經充分的瞭解了DataSnap的回叫功能了,也許您可以自己試著完成一個小功課,請繼續修改範例DataSnap伺服器和用戶端應用程式讓用戶端應用程式可以註冊不同的回叫通道而不像前面的範例應用程式只使用固定的DemoChannel這個回叫通道,如何? 應該不算太難而且應該很有趣吧。

 

DataSnap XE回叫功能最有意思的是還可以使用於瀏覽器型態的應用程式以開發輕薄型回叫DataSnap用戶端, 這是更深入的回叫機制了, 我們有機會再談吧.

Have Fun!

4 則迴響

進階DataSnap回叫功能

Delphi/C++Builder 2010加入了回叫機制, 我也在2009年的部落格文章中說明了如何使用Delphi/C++Builder 2010的回叫功. 然而Delphi/C++Builder XE又再次強化了回叫機制, 讓這個功能更為強大和完善, 由於XE版的回叫機制提供了眾多新的功能, 因此我想藉由這篇文章說明一下如何使用XE版的回叫機制, 雖然我無法一次把所有的功能寫完, 但起個頭還是很有用的.

DataSnap XE在原有的基礎回叫機制之上加入了許多強大的新功能,從DataSnap XE開始開發人員可以使用下面的回叫功能:

  • 用戶端可向伺服端註冊回叫通道,如此一來伺服器可以一次回叫所有在同回叫通道中所有註冊的用戶端回叫函式
  • 用戶端可以同時註冊多個不同的回叫通道
  • 用戶端可以藉由回叫通道呼叫不同的用戶端
  • 新增回叫元件以幫助開發人員簡化開發回叫機制

DataSnap XE新的回叫功能雖然很多,但使用起來仍然相當的容易,下面說明了如何使用這些DataSnap XE新的回叫功能的基本步驟:

  • 用戶端使用TDSClientCallbackChannelManager向伺服器註冊一個回叫通道
  • 伺服器使用TDSServer元件的BroadcastMessage方法回叫所有註冊的用戶端

當然,開發人員可以更進一步的使用DataSnap XE進階的回叫功能,不過在那之前也許我們應該先說明數個範例讓讀者瞭解如何使用這些基本的步驟。

開發回叫DataSnap伺服器

在Delphi整合發展環境中建立一個DataSnap Server專案:

在設定此伺服器的特性時,讓我們目前只選擇使用TCP/IP通訊協定,如下圖所示:

開啟專案中的ServerContainer程式單元,此時在ServerContainer中產生了兩個元件,TDSServer以及TDSTCPServerTransport,由於接下來我們將先展示Windows用戶端的回叫功能,因此現在使用TCP/IP通訊協定就足夠了。

現在開啟專案主表單,並且在其中置入如下的元件:

主表格上方使用了TListBox元件,它可以顯示所有用戶端註冊的回叫識別ID,而下方的TMemo元件則是使用來回叫註冊用戶端,在稍後我們將在此TMemo元件中輸入資訊,這些輸入的資訊就會藉由回叫通道自動傳遞給用戶端。

DataSnap伺服器要回叫所有註冊的用戶端是非常容易的,只需要藉由TDSServer類別定義的BroadcastMessage方法即可,TDSServer類別中定義了兩個BroadcastMessage方法原型如下:

function BroadcastMessage(const ChannelName: String; const Msg: TJSONValue; const ArgType: Integer = TDBXCallback.ArgJson): boolean; overload;

 

function BroadcastMessage(const ChannelName: String; const CallbackId: String; const Msg: TJSONValue; const ArgType: Integer = TDBXCallback.ArgJson): boolean; overload;

這兩個BroadcastMessage方法的差異在於上述第一個BroadcastMessage可以傳遞訊息給它第一個參數ChannelName指定的通道中所有的回叫用戶端,而第二個BroadcastMessage方法則是只傳遞訊息給它第一個參數ChannelName指定的通道中由第二個參數CallbackId指定的回叫用戶端,最後這個兩個BroadcastMessage方法傳遞給用戶端的訊息則由第二個參數Msg封裝。

瞭解了如何使用BroadcastMessage方法之後,我們就可以看看如何把DataSnap伺服器中於TMemo元件中輸入的訊息傳遞給回叫用戶端。現在為主表單中的TMemo元件實作OnChange事件處理函式如下:

001    procedure TForm17.mmMessageChange(Sender: TObject);

002    var

003      vMessage : TJSONString;

004    begin

005      vMessage := TJSONString.Create(mmMessage.Lines.Text);

006      ServerContainer5.DSServer1.BroadcastMessage(DEMOChannel, vMessage);

007    end;

在005行我們把輸入於TMemo(mmMessage)中的資訊以TJSONString物件封裝,然後在006行藉由呼叫ServerContainer中的TDSServer元件的BroadcastMessage方法傳遞給所有註冊的用戶端。但誰是註冊的用戶端呢?請看BroadcastMessage的第一個參數DEMOChannel,這代表DataSnap伺服器會傳遞資訊給所有在DEMOChannel通道中註冊的用戶端。而DEMOChannel是一個通道的名稱,我們在DataSnap伺服器中定義它如下:

const

DEMOChannel = ‘DemoChannel’;

因此用戶端只要使用這個名稱向伺服器註冊回叫通道的話,就可以讓DataSnap伺服器回叫用戶端,當然也用戶端可以先向伺服器查詢已經定義在DataSnap伺服器中的回叫通道名稱,或是由用戶端自行在DataSnap伺服器中建立指定名稱的回叫通道。

由於回叫用戶端是向DataSnap伺服器中指定名稱的回叫通道註冊,而且每一個用戶端都使用一個特定的回叫識別ID來代表,因此我們也可以藉由TDSServer元件來查詢某一個名稱的回叫通道中所有註冊的用戶端回叫識別ID。

此範例DataSnap伺服器主表單中的『列出所有回叫識別』按鈕的OnClick事件處理函式就可以在主表單上方的TListBox中列出特定回叫通道中所有的用戶端回叫識別ID,下面就是它的OnClick實作程式碼:

001    procedure TForm17.Button1Click(Sender: TObject);

002    var

003      aIdList : TList<String>;

004      sId : String;

005    begin

006      aIdList := ServerContainer5.DSServer1.GetAllChannelCallbackId(DEMOChannel);

007      try

008        for sId in aIdList do

009          ListBox1.Items.Add(sId);

010      finally

011        aIdList.Free;

012      end

013    end;

GetAllChannelCallbackId方法會回傳TList<String>型態的執行結果,其中即包含了所有在此通道名稱中註冊的用戶端回叫識別ID,因此在006行藉由TDSServer元件呼叫GetAllChannelCallbackId之後,就可以取得到在DEMOChannel中註冊的識別ID,接著從008行到012行就把這些識別ID顯示在主表單的TListBox中。

現在請編譯並且執行此範例DataSnap伺服器,接著我們就可以實作回叫用戶端了,首先讓我們先說明如何建立Windows應用程式型態的用戶端,接著再說明如何建立瀏覽器型態的用戶端。

開發回叫DataSnap用戶端

在專案管理員中再建立一個VCL Form應用程式專案,並且在其中放入TSQLConnection,TDSClientCallbackChannelManager,TMemo,兩個TButton元件,如下圖所示。其中TSQLConnection是連結上一小節的範例DataSnap伺服器,而TDSClientCallbackChannelManager則是使用來向DataSnap伺服器註冊回叫用戶端的元件。

接著設定TDSClientCallbackChannelManager特性值如下:

特性名稱 特性值
ChannelName DemoChannel
CommunicationProtocol tcp/ip
DSHostname localhost
DSPort 211
Name DemoChannelManager

設定TDSClientCallbackChannelManager的ChannelName特性值為DemoChannel是因為前面範例DataSnap伺服器使用的通道名稱就是DemoChannel,而且前面範例DataSnap伺服器是支援TCP/IP通訊協定和使用211通信埠,因此我們需要設定TDSClientCallbackChannelManager相對應的特性值,下圖顯示了在物件檢視器中設定TDSClientCallbackChannelManager元件的特性值:

設定好TDSClientCallbackChannelManager元件之後,我們就可以看看用戶端主表單中的『啟動回叫功能』按鈕的實作程式碼了:

001    procedure TfmMainForm.btnStartClick(Sender: TObject);

002    begin

003      SetupTask;

004      EnableDisableButtons(False, True);

005      DemoChannelManager.RegisterCallback(callbackId, TDemoCallback.Create)

006    end;

007

008    procedure TfmMainForm.SetupTask;

009    begin

010      if not scnnCallbackServer.Connected then

011      begin

012        scnnCallbackServer.Connected := True;

013      end;

014      callbackId := DateTimeToStr(Now);

015      Self.Caption := callbackId;

016    end;

在btnStartClick事件處理函式中先於003行呼叫SetupTask方法以開啟TSQLConnection元件連結範例DataSnap伺服器,並且在014行根據目前的時間建立一個獨特的識別ID,callbackId。最後在005行呼叫TDSClientCallbackChannelManager元件的RegisterCallback方法向範例DataSnap伺服器註冊這個回叫用戶端。

TDSClientCallbackChannelManager元件的RegisterCallback方法原型定義如下:

function RegisterCallback(const CallbackId: String; const Callback: TDBXCallback): boolean; overload;

RegisterCallback接受兩個參數,第一個是每一個回叫用戶端的識別ID,第二個參數則是型態為TDBXCallback的物件,在前面的小節中我們已經解釋過TDBXCallback類別,因此在這裡我們需要建立一個從TDBXCallback衍生類別的物件,在這個衍生類別中我們需要複載虛擬方法Execute,如此一來範例DataSnap伺服器就可以藉由呼叫複載虛的擬方法Execute來呼叫到用戶端。

由於我們在上面的005行是傳遞TDemoCallback物件給RegisterCallback方法,因此我們需要在這個範例用戶端應用程式中定義和實作TDemoCallback類別,它需要從TDBXCallback繼承下來:

type

TDemoCallback = class(TDBXCallback)

public

constructor Create;

function Execute(const Arg: TJSONValue): TJSONValue; override;

end;

TDemoCallback需要實作虛擬方法Execute,當DataSnap伺服器回叫用戶端時就會執行虛擬方法Execute。由於在這個範例中我們希望範例DataSnap伺服器在TMemo中輸入的資訊能夠立刻顯示在用戶端,因此我們實作虛擬方法Execute如下:

001    function TDemoCallback.Execute(const Arg: TJSONValue): TJSONValue;

002    var

003      sDemoMessage : String;

004    begin

005      Result := TJSONTrue.Create;

006

007      if (Arg is TJSONString) then

008      begin

009        sDemoMessage := TJSONString(Arg).Value;

010        TThread.Synchronize(nil,

011                            procedure

012                            begin

013                              fmMainForm.mmDemoMessage.Lines.Text := sDemoMessage;

014                            end

015                            );

016      end;

017    end;

當DataSnap伺服器藉由回叫功能呼叫用戶端複載的Execute時,DataSnap伺服器可以把伺服端傳遞到用戶端的資訊封裝在Execute的參數Arg中。由於在前面的範例DataSnap伺服器是把在伺服端TMemo中的資訊封裝成TJSONString傳遞到用戶端,因此在007行先判斷伺服端傳遞來的是否是TJSONString型態,如果是的話,就00行取出伺服端傳遞來的資訊,接著由於我們需要把這個資訊顯示在用戶端主表單中的TMemo元件中,因此我們藉由呼叫TThread類別的類別方法Synchronize來更新用戶端的使用者介面(這是因為用戶端使用者介面的主執行緒和在背景的回叫執行緒是不同的,因此需要使用Synchronize來讓背景回叫執行緒更新主執行緒中的元件)。由於Synchronize定義了如下的原型:

class procedure TThread.Synchronize(AThread: TThread; AMethod: TThreadMethod);

因此在上面的010行中我們直接使用匿名方法來更新主表單的TMemo元件。

最後當我們不再需要讓用戶端被回叫時,可以呼叫TDSClientCallbackChannelManager元件的UnregisterCallback方法並且傳遞用戶端識別ID,例如下面的程式碼就是主表單中『停止回叫功能』按鈕OnClick事件處理函式的實作程式碼:

procedure TfmMainForm.btnStopClick(Sender: TObject);

begin

EnableDisableButtons(True ,False);

DemoChannelManager.UnregisterCallback(callbackId);

end;

現在編譯並且執行此範例回叫用戶端,從下圖我們可以看到,點選範例DataSnap伺服器中的『列出所有回叫識別』按鈕就可以在上方的TListBox中列出用戶端傳遞來的識別ID,而且只要用戶端應用程式點選了主表單中的『啟動回叫功能』按鈕註冊回叫用戶端,那麼我們在範例DataSnap伺服器的TMemo中輸入的任何資訊就會立刻顯示在用戶端應用程式的TMemo元件中,證明了回叫功能是成功的。

當然,用戶端可以註冊多個不同的回叫通道,在同一個回叫通道中也可以註冊多個識別ID,例如讓我們修改剛才的範例用戶端應用程式,加入另外一個TMemo元件,以及一個TEdit元件讓使用者可以輸入不同的用戶端識別ID來註冊:

接著在『啟動回叫功能1』和『啟動回叫功能2』按鈕中都使用下面的程式碼實作,現在用戶端識別ID就由使用者輸入而不是使用目前的日期:

procedure TfmMainForm.btnStartClick(Sender: TObject);

begin

SetupTask;

EnableDisableButtons(False, True, True);

DemoChannelManager.RegisterCallback(edtCallbackId.Text, TDemoCallback.Create);

aIdList.Add(edtCallbackId.Text);

end;

編譯並且執行新的用戶端應用程式,在下面的圖形中我們可以看到筆者在用戶端應用程式中註冊了兩個用戶端識別ID,分別是『用戶端識別ID1』和『用戶端識別ID2』,而範例DataSnap伺服器也可以列出這兩個不同的用戶端識別ID,在用戶端註冊了兩個不同的識別ID之後,範例DataSnap伺服器可以藉由同時回叫這兩個不同的用戶端回叫物件。例如下圖就顯示了當我們在範例DataSnap伺服器的TMemo中輸入了訊息之後,這些訊息會立刻顯示在用戶端應用程式中兩個不同的TMemo元件之中:

如何? DataSnap XE的回叫機制是不是更強大了?不過故事還沒結束,接下來我們將繼續討論如何讓不同的用戶端都能夠藉由回叫機制來溝通,以及如何開發以瀏覽器為基礎的回叫用戶端,這些是更精彩的主題,我們下次再見了, Have Fun!

 

2 則迴響