簡體   English   中英

Delphi-異步Datasnap方法調用

[英]Delphi - Asynchronous Datasnap Method Calls

我正在編寫一個Datasnap應用程序,該服務器在客戶端/服務器之間具有TCP連接,並且服務器已連接到SQL Server。

服務器具有帶有所有數據集查詢和SQL連接的數據模塊DM1。 DM1還具有REST請求/客戶端/響應組件。

DM1具有公開的函數ID參數為PostDataAsync:從數據集生成json,然后HTTP將其發布到RESTFul服務。 它返回未能在回調arg中發布的記錄數。

該DM1的DSServer為“調用”。

調用服務器類型應確保每個服務器方法調用具有其自己的數據庫連接,數據集,Rest組件,而這些組件不會有多個調用而相互干擾(如果添加了並行線程)。

procedure TServerMethods1.postCustOrderHistAsync(CustomerID: String; callback: TDBXcallback);
var
  jsonObject: TJSONObject;
  CallbackValue: TJsonValue;
  errors: Integer;
begin
  errors := postCustOrderHist(CustomerID); //takes time to post, returns num of failed records
  jsonObject := TJSONObject.create;
  jsonObject.AddPair(tjsonpair.create('errors', errors.ToString));
  CallbackValue := callback.Execute(jsonObject);
end;

客戶端有一個按鈕,該按鈕調用帶有ID參數的服務器方法PostDataAsync,還有一個回調函數“ ShowNotification”(使用Windows通知中心顯示“通知”狀態)。

現在,該應用程序的工作方式如下:客戶端同步調用服務器功能,這意味着主線程等待服務器功能完成HTTP發布,然后運行回調通知。 同時客戶端掛起。

TDSCallbackWithMethod = class(TDBXCallback)
private
  FCallbackMethod: TDSCallbackMethod;
public
  constructor Create(ACallbackMethod: TDSCallbackMethod);
  function Execute(const Args: TJSONValue): TJSONValue; override; //executes FCallbackMethod
end;

procedure TMainForm.BtnPostOrderHistoryClick(Sender: TObject);
var
  callback: TDBXCallback;
  ServerMethods1Client: TServerMethods1Client;
begin
  //Define Callback to show notification
  callback := TDSCallbackWithMethod.Create(
    function(const Args: TJSONValue): TJSONValue
    var
      errors: integer;
    begin
      errors := Args.GetValue<integer>('errors');

      if errors = 0 then
        showNotification(StrSentSuccessfully)
      else
        showNotification(StrSendingFailed + '(' + errors.ToString + ' not sent)');

      result := TJsonTrue.Create;
    end);

  //Call Server Method
  ServerMethods1Client := TServerMethods1Client.Create(DMServerConnection.SQLConnection1.DBXConnection);
  try
    ServerMethods1Client.postCustOrderHistAsync(EditCustomerId.Text, callback)
  finally
    ServerMethods1Client.Free;
  end;
end;

設計應如何以異步方式調用服務器方法,並在完成后讓服務器運行回調? Post函數應該能夠由同一用戶多次調用或同時多次調用。 線程應該在服務器端還是在客戶端? 如果有人可以提供幫助,我可以使用Northwind數據庫發送該應用程序的演示。

注意:我嘗試在TTask中運行客戶端函數調用,當用戶一次運​​行一次該函數時,該函數就起作用。 但是,當服務器方法同時運行幾次時,我會收到“ DBXError…讀取錯誤……回調,期望X得到Y”。 客戶端在等待第一個請求的響應回調格式時,似乎與從第二個請求啟動的其他tcp協議包混淆了。 我嘗試在服務器端運行ttask,但出現異常“ TOLEDBCommand.Destroy-接口未釋放”

查看示例,它逐步完成了創建回調的步驟。 基本上,您需要一個TDSClientCallbackChannelManager(組件)及其RegisterCallback函數,以告知datasnap客戶端從服務器觸發回調時在客戶端調用哪種方法(從TDBXCallback繼承的對象)。 您將需要將客戶端會話ID傳遞到服務器,以便它可以通過NotifyCallBack調用正確的客戶端。 然后,從該回調方法中,您可以在TThread.Queue中執行所需操作以確保安全。 您可能需要在服務器返回的JSON中創建某種唯一的標識符(或者您的CustomerID可以使用),以便您的客戶端知道哪個調用是哪個結果。

為了簡化客戶端服務器方法的調用,我從客戶端刪除了Callback,並創建了並行線程來等待服務器的響應。 我仍然遇到相同的錯誤“ DBXError…讀取錯誤…期望X得到Y的回調”。 因此,當我知道錯誤不是回調問題時,這是線程之間的干擾。 原來,當我創建客戶端的代理方法時,所有線程都使用相同的DBXConnection實例。 這將導致在不同服務器調用/響應之間丟失SQLconnection並獲得解析錯誤。 我做了一個函數“ getNewSqlConnection”,它將把TSQLConnection的所有設置復制到一個新實例中。
現在,客戶端調用方法如下所示:

procedure TMainForm.BtnPostOrderHistoryClick(Sender: TObject);
begin
  ttask.Run(
    procedure
    var
      ServerMethods1Client: TServerMethods1Client;
      SqlConnectionLocal: TSqlConnection;
      errors: Integer;
    begin
      // Call Server Method
      SqlConnectionLocal := DMServerConnection.getNewSqlConnection(Self);
      ServerMethods1Client := TServerMethods1Client.Create(SqlConnectionLocal.DBXConnection);
      try
        errors := ServerMethods1Client.postCustOrderHist(EditCustomerId.Text);
        if errors = 0 then
          TThread.Synchronize(nil,
            Procedure
            begin
              showNotification(StrSentSuccessfully)
            end)
        else
          TThread.Synchronize(nil,
            Procedure
            begin
              showNotification(StrSendingFailed + '(' + errors.ToString + ' not sent)')
            end);
      finally
        ServerMethods1Client.Free;
        SqlConnectionLocal.Free;
      end;
    end);
end;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM