チュートリアル:アプリケーションで DataSnap サーバーを使用する

提供:RAD Studio

データベースおよび LiveBinding のチュートリアル への移動


DataSnap 技術により、インターネット、ローカル ネットワークまたはローカル ホスト内を通信する、クライアントサーバー型アプリケーションを作成できます。

次のサンプルでは、簡単なローカルのクライアントサーバー型アプリケーションを作成するときの DataSnap の使用方法について示します。 クライアント アプリケーションとサーバー アプリケーションの両方とも Delphi で実装されています。 サーバーを作成し、クライアントとサーバー間の接続を DataSnap でアクティブにした後に、サーバーで定義され、実装されているメソッドを、クライアントが呼び出すことができます。

サーバーは Delphi と C++ のいずれでも実装できます。 この例では両方を示します。 クライアントを同じ言語で実装する必要はありません。 DataSnap では、Delphi でサーバーを、C++ でクライアントを実装することも、その逆の組み合わせにすることも可能です。

DataSnap サーバーの主要コンポーネント

主なコンポーネントは以下のとおりです。

TDSServer コンポーネントは、DataSnap サーバー アプリケーションの中心ロジックです。 これには、サーバーを開始および停止する、Start と Stop メソッドが含まれています。 また、AutoStart プロパティもあります。 デフォルトでは、AutoStart の値は True に設定されており、サーバーは、アプリケーションの起動時に自動的に立ち上がります。 1 つのサーバー アプリケーションにつき、TDSServer コンポーネントが 1 つ必要となります。

TDSServerClass コンポーネントは、サーバー クラスを表します。

DataSnap サーバーはサーバー クラスのインスタンスを自動的に作成し、破棄します。 サーバー クラスのインスタンスは、TDSServerClass コンポーネントのLifeCycle プロパティによって制御されます。 LifeCycle プロパティに指定できる値は次の3つです: Server、Session、Invocation。

  • LifeCycle を Server に設定すると、DataSnap サーバーは、サーバー アプリケーションに接続するすべてのクライアントが使用する、サーバー クラスのインスタンスを 1 つ作成します。 これは "シングルトン" パターンを表します。 Server ライフ サイクルを使用するときには注意してください。ユーザーのサーバー クラスをスレッドセーフで実装する必要があるからです。 つまり、複数のスレッドから同時にアクセスできるように、サーバー クラスを設計する必要があります。
  • LifeCycle のデフォルト値は、Session です。 つまり、DataSnap サーバーは各接続クライアントに対して、サーバー クラスのインスタンスを 1 つ作成します。
  • LifeCycle プロパティの 3 番目の値は、Invocation です。 この場合、サーバー クラスのインスタンスは、クライアントからメソッド呼び出しが到着するたびに作成され、破棄されます。サーバー クラスの状態はメソッド呼び出しの間では保持されません。

クライアントとサーバー間の通信を実行するためにコンポーネントも必要です。

TDSTCPServerTransport コンポーネントは、複数スレッドでクライアント接続を受信するためにリスンする、マルチスレッドの TCP サーバーを実装します。 このコンポーネントには、イベントがありません。 Port プロパティは、使用する TCP ポートを示します。 デフォルトのポート番号は 211 です。 クライアントとサーバー間の通信に HTTP を使用することもできます。

サーバー アプリケーションの作成

  1. プロジェクトを新規作成します。
    • Delphi の場合、メイン メニューから、[ファイル|新規作成|VCL フォーム アプリケーション - Delphi] を選択します。
    • C++ の場合、メイン メニューから、[ファイル|新規作成|VCL フォーム アプリケーション - C++Builder] を選択します。
    フォームの Caption プロパティを ServerForm に変更します。
  2. 次のコンポーネント(ツール パレットの Datasnap Server カテゴリ)をフォームに配置します。
メイン メニュー項目の[ファイル|すべて保存]をクリックします。 ファイルを MyServer、プロジェクトを MyServerProj として保存します。
この時点で、サーバー アプリケーションは次のようになっています。



次に示す手順に従って、3 つのコンポーネントを互いにリンクします。
  • TDSServerClass コンポーネントをフォーム上で選択します。 Server プロパティを TDSServer コンポーネントの名前に設定します(この例の場合、DSServer1)。
  • TDSTCPServerTransport コンポーネントをフォーム上で選択します。 Server プロパティを TDSServer コンポーネントの名前に設定します(この例の場合、DSServer1)。
  1. 新しいユニットをプロジェクトに追加します。
    • Delphi の場合、メイン メニューから、[ファイル|新規作成|ユニット - Delphi] を選択します。
    • C++ の場合、メイン メニューから、[ファイル|新規作成|ユニット - C++Builder]を選択します。
    ユニットを Delphi ファイル MyClass.pas、または C++ ファイル MyClass.cpp に保存します。 このユニットには、クライアント アプリケーションで使用するサーバーのクラスの実装が含まれます。 この例では、次のコードは、1 つのメソッド(2 つの浮動小数点数を合計する)を含む MyClass というクラスの実装を表します。
    Delphi
    unit MyClass;
    
    interface
    uses Classes;
    type
      {$METHODINFO ON}
      TMyClass = class(TComponent)
        function Sum(const A, B: Double): Double;
      end;
      {$METHODINFO OFF}
    
    implementation
    { TMyClass }
    function TMyClass.Sum(const A, B: Double): Double;
    begin
      Result := A + B;
    end;
    
    end.
    

    メモ: {$METHODINFO ON} 指令は、Datasnap サーバーが必要とする実行時情報を生成させます。このため、これは必須で、単なるコメントではありません。 詳細は、「METHODINFO 指令(Delphi)」を参照してください。


     


    C++

    MyClass.h に次のコードを記述します。

    #include <DSServer.hpp>
    
    class DECLSPEC_DRTTI TMyClass : public TComponent
    {
    private:
    public:
      double Sum(const double A, const double B);
    };
    #endif
    

    MyClass.cpp に次のコードを記述します。

    double TMyClass::Sum(const double A, const double B)
    {
      return A + B;
    }
    

    メモ: C++ アプリケーション設計時に、DataSnap で RTTI がサポートされるようになりました。 DECLSPEC_DRTTI 宣言では、Delphi の {$METHODINFO ON} 指令と同様に、Datasnap サーバーで必要な実行時情報が生成されます。これは必須です。


    • Delphi では、このユニットの名前 MyClass をサーバー アプリケーションのユニット MyServer.pas の uses 句に追加します。
    • C++ では、次の行を MyServer.h に追加します。
    #include "MyClass.h"
    
  2. クライアント アプリケーションから呼び出したいクラスを指定するには、TDSServerClass コンポーネントの OnGetClass イベントを定義します。 MyServer の[デザイン]タブで次のとおり実行します。
    1. TDSServerClass コンポーネントをフォーム上で選択します。
    2. [イベント]タブをオブジェクト インスペクタで選択します。
    3. OnGetClass イベントの値をダブルクリックします。
    4. ちょうど生成された関数で、PersistentClass を設定する、1 行のコードを追加します。
    Delphi
    procedure TForm1.DSServerClass1GetClass(DSServerClass: TDSServerClass;
      var PersistentClass: TPersistentClass);
    begin
      PersistentClass := TMyClass;
    end;
    


    C++

    void __fastcall TForm1::DSServerClass1GetClass(TDSServerClass *DSServerClass, TPersistentClass &PersistentClass)
    
    {
      PersistentClass = __classid(TMyClass);
    }
    
    このイベントを実装しないと、起動直後に、アプリケーションから、次のメッセージとともに TDBXError 例外が発生します。

    OnGetClass event not set or it did not provide a class reference (OnGetClass イベントが設定されていないか、クラス参照がありません)

    OnGetClass イベントには、参照として渡される PersistentClass 引数があります。 イベント ハンドラのコードで、開発者は PersistentClass にサーバー クラスへのクラス参照を割り当てる必要があります(前のサンプルを参照)。
    これが DataSnap アーキテクチャを理解するために必要な重要概念です。 クラス参照が PersistentClass に割り当てられます。オブジェクト参照ではありません。

これでサーバー アプリケーションの実装は完了です。

クライアント アプリケーションの作成

  1. クライアント アプリケーションをサーバー アプリケーションと同じプロジェクト グループで作成するには、プロジェクト マネージャのプロジェクト グループ名を右クリックして、コンテキスト メニューから[新規プロジェクトの追加...]を選択するか、メイン メニューから[プロジェクト|新規プロジェクトの追加...]を選択します。[項目の新規作成] ダイアログ ボックスが開きます。
    • Delphi では、[Delphi プロジェクト]カテゴリを選択してから、[VCL フォーム アプリケーション]を選択し、[OK]をクリックします。
    • C++ の場合、[C++Builder プロジェクト]カテゴリを選択してから、[VCL フォーム アプリケーション]を選択し、[OK]をクリックします。
    フォームの Caption および Name プロパティに ClientForm を設定します。 メイン メニュー項目の[ファイル|すべて保存]をクリックします。 ファイルを MyClient、プロジェクトを MyClientProj として保存します。 プロジェクト グループを DSServerExample として保存します。
  2. データを入力し、結果を書き込むコントロール(合計計算用のボタン、ラベル、編集ボックス)をクライアント フォームに次の図のように配置します。 ラベル A の隣にある TEdit の Name プロパティを EditA に、B の TEdit の Name を EditB に変更します。 Result TEdit の Name を、EditResult に設定します。 すべての TEdit コントロールの Text プロパティを、空に変更します。 TButton の Caption を Calculate に設定します。
  3. TSQLConnection コンポーネントを、ツール パレット dbExpress カテゴリから追加します。 TSQLConnection の次のプロパティを設定します。
    • Driver: Datasnap(クライアント側からみると、このプロバイダはデータベースへの接続と同様であるが、実際には、DataSnap サーバーへの接続)
    • LoginPrompt: False(オプション、クライアントがサーバーに接続するたびにユーザー名とパスワード用のダイアログが表示されない)
クライアント フォームは次のようになります:



  1. クライアントサーバー型アプリケーションを作成するときの一番重要な手順は、サーバーで実装されるすべての機能のプロトタイプを含むインターフェイスを作成することです。 次のとおり実行します。
    • プロジェクト マネージャで、サーバー プロジェクト MyServerProj の名前をダブルクリックして、サーバー プロジェクトを選択します。
    • [実行|デバッガを使わずに実行]をメイン メニューから選択し、サーバーを実行します。 表示される[ServerForm]ダイアログを最小化できます。
    • サーバー実行中に、プロジェクト マネージャで、名前 MyClientProj をダブルクリックして、クライアント プロジェクトを選択します。
    • [デザイン]タブで、TSQLConnection コンポーネントの Connected プロパティを、True に設定します。
    • クライアント フォームの TSQLConnection コンポーネントを右クリックし、そのコンテキスト メニューから、[DataSnap クライアント クラスの生成]をクリックします。 新しいユニットがユーザーのクライアント プロジェクトに追加されます。サーバーで実装されたクラスに関する情報と、これらのクラスに含まれるすべてのメソッドが含まれます。
      • Delphi では、新規ユニットを MyDSClient.pas として保存し、このユニット名 MyDSClient を MyClient.pas のユニットのリストに追加します。
      • C++ の場合は、新規ユニットを MyDSClient.cpp として保存します。 #include "MyDSClient.h" 行を MyClient.cpp の先頭に追加します。
  2. クライアント アプリケーションで必要なメソッドを呼び出します。 この例では、OnClick イベントを TButton コンポーネントに対して実装し、自動生成された DataSnap クライアント ユニットの Sum メソッドを呼び出します。 ここで、生成クラスは TMyClassClient であり、ボタンのイベント ハンドラは TClientForm.CalculateClick(Delphi)またはTClientForm::Button1Click(C++)です。 Delphi
    procedure TClientForm.CalculateClick(Sender: TObject);
    var
      Temp: TMyClassClient;
      A, B: Double;
    begin
      Temp := TMyClassClient.Create(SQLConnection1.DBXConnection);
    try
      A := StrToFloat(EditA.Text);
      B := StrToFloat(EditB.Text);
      EditResult.Text := FloatToStr(Temp.Sum(A, B));
    finally
      Temp.Free;
    end;
    


    C++

    void __fastcall TClientForm::Button1Click(TObject *Sender)
    {
      TMyClassClient *Temp;
      double A, B;
    
      Temp = new TMyClassClient(SQLConnection1->DBXConnection);
      try
      {
        A = StrToFloat(EditA->Text);
        B = StrToFloat(EditB->Text);
        EditResult->Text = FloatToStr(Temp->Sum(A, B));
      }
      __finally
      {
        delete Temp;
      }
    }
    
  3. 最後に、クライアント アプリケーションをビルドし実行します。 クライアント フォームが表示されます。 A と B の各フィールドに 10 進数を入力し、[Calculate] ボタンをクリックします。合計が Result フィールドに表示されます。 次のエラー メッセージが表示された場合は、
    Connection cannot be nil. Make sure the connection has been opened.(接続に nil を指定できません。接続が開いていることを確認してください。) TSQLConnection コンポーネントの Connected プロパティが、True に設定されていない可能性があります。



メモ: サーバー アプリケーションを終了する前に、すべての SQL 接続を必ず閉じてください。 この例では、クライアントの TSQLConnection コンポーネントの Connected プロパティを、False に設定します。 DataSnap では中断している接続に関する警告が表示されません。したがって、サーバーが閉じられているように見える場合でも、サーバーへの接続がなくなるまで、サーバーは終了しません。 すべてのクライアント アプリケーションを閉じても、この問題の解決になりません。 Delphi IDE からサーバーへの接続を自動的に開き、公開されたクラスとメソッドを参照できるからです。

関連項目