チュートリアル:アプリケーションで DataSnap サーバーを使用する
データベースおよび 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 を使用することもできます。
サーバー アプリケーションの作成
- プロジェクトを新規作成します。
- Delphi の場合、メイン メニューから、[ファイル|新規作成|VCL フォーム アプリケーション - Delphi] を選択します。
- C++ の場合、メイン メニューから、[ファイル|新規作成|VCL フォーム アプリケーション - C++Builder] を選択します。
- フォームの Caption プロパティを ServerForm に変更します。
- 次のコンポーネント(ツール パレットの Datasnap Server カテゴリ)をフォームに配置します。
-
- メイン メニュー項目の[ファイル|すべて保存]をクリックします。 ファイルを MyServer、プロジェクトを MyServerProj として保存します。
-
- この時点で、サーバー アプリケーションは次のようになっています。
-
- 次に示す手順に従って、3 つのコンポーネントを互いにリンクします。
-
-
- TDSServerClass コンポーネントをフォーム上で選択します。 Server プロパティを TDSServer コンポーネントの名前に設定します(この例の場合、DSServer1)。
- TDSTCPServerTransport コンポーネントをフォーム上で選択します。 Server プロパティを TDSServer コンポーネントの名前に設定します(この例の場合、DSServer1)。
-
-
新しいユニットをプロジェクトに追加します。
- Delphi の場合、メイン メニューから、[ファイル|新規作成|ユニット - Delphi] を選択します。
- C++ の場合、メイン メニューから、[ファイル|新規作成|ユニット - C++Builder]を選択します。
Delphiunit 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"
- クライアント アプリケーションから呼び出したいクラスを指定するには、TDSServerClass コンポーネントの OnGetClass イベントを定義します。 MyServer の[デザイン]タブで次のとおり実行します。
- TDSServerClass コンポーネントをフォーム上で選択します。
- [イベント]タブをオブジェクト インスペクタで選択します。
- OnGetClass イベントの値をダブルクリックします。
- ちょうど生成された関数で、
PersistentClass
を設定する、1 行のコードを追加します。
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
に割り当てられます。オブジェクト参照ではありません。
これでサーバー アプリケーションの実装は完了です。
クライアント アプリケーションの作成
- クライアント アプリケーションをサーバー アプリケーションと同じプロジェクト グループで作成するには、プロジェクト マネージャのプロジェクト グループ名を右クリックして、コンテキスト メニューから[新規プロジェクトの追加...]を選択するか、メイン メニューから[プロジェクト|新規プロジェクトの追加...]を選択します。[項目の新規作成] ダイアログ ボックスが開きます。
- Delphi では、[Delphi プロジェクト]カテゴリを選択してから、[VCL フォーム アプリケーション]を選択し、[OK]をクリックします。
- C++ の場合、[C++Builder プロジェクト]カテゴリを選択してから、[VCL フォーム アプリケーション]を選択し、[OK]をクリックします。
- フォームの Caption および Name プロパティに ClientForm を設定します。 メイン メニュー項目の[ファイル|すべて保存]をクリックします。 ファイルを MyClient、プロジェクトを MyClientProj として保存します。 プロジェクト グループを DSServerExample として保存します。
- データを入力し、結果を書き込むコントロール(合計計算用のボタン、ラベル、編集ボックス)をクライアント フォームに次の図のように配置します。 ラベル A の隣にある TEdit の Name プロパティを EditA に、B の TEdit の Name を EditB に変更します。 Result TEdit の Name を、EditResult に設定します。 すべての TEdit コントロールの Text プロパティを、空に変更します。 TButton の Caption を Calculate に設定します。
- TSQLConnection コンポーネントを、ツール パレット dbExpress カテゴリから追加します。 TSQLConnection の次のプロパティを設定します。
- Driver: Datasnap(クライアント側からみると、このプロバイダはデータベースへの接続と同様であるが、実際には、DataSnap サーバーへの接続)
- LoginPrompt: False(オプション、クライアントがサーバーに接続するたびにユーザー名とパスワード用のダイアログが表示されない)
-
- クライアント フォームは次のようになります:
- クライアントサーバー型アプリケーションを作成するときの一番重要な手順は、サーバーで実装されるすべての機能のプロトタイプを含むインターフェイスを作成することです。 次のとおり実行します。
-
- プロジェクト マネージャで、サーバー プロジェクト MyServerProj の名前をダブルクリックして、サーバー プロジェクトを選択します。
- [実行|デバッガを使わずに実行]をメイン メニューから選択し、サーバーを実行します。 表示される[ServerForm]ダイアログを最小化できます。
- サーバー実行中に、プロジェクト マネージャで、名前 MyClientProj をダブルクリックして、クライアント プロジェクトを選択します。
- [デザイン]タブで、TSQLConnection コンポーネントの Connected プロパティを、True に設定します。
- クライアント フォームの TSQLConnection コンポーネントを右クリックし、そのコンテキスト メニューから、[DataSnap クライアント クラスの生成]をクリックします。 新しいユニットがユーザーのクライアント プロジェクトに追加されます。サーバーで実装されたクラスに関する情報と、これらのクラスに含まれるすべてのメソッドが含まれます。
- Delphi では、新規ユニットを MyDSClient.pas として保存し、このユニット名 MyDSClient を MyClient.pas のユニットのリストに追加します。
- C++ の場合は、新規ユニットを MyDSClient.cpp として保存します。
#include "MyDSClient.h"
行を MyClient.cpp の先頭に追加します。
-
- クライアント アプリケーションで必要なメソッドを呼び出します。 この例では、OnClick イベントを TButton コンポーネントに対して実装し、自動生成された DataSnap クライアント ユニットの Sum メソッドを呼び出します。 ここで、生成クラスは
TMyClassClient
であり、ボタンのイベント ハンドラはTClientForm.CalculateClick
(Delphi)またはTClientForm::Button1Click
(C++)です。 Delphiprocedure 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; } }
- 最後に、クライアント アプリケーションをビルドし実行します。 クライアント フォームが表示されます。 A と B の各フィールドに 10 進数を入力し、[Calculate] ボタンをクリックします。合計が Result フィールドに表示されます。
次のエラー メッセージが表示された場合は、
メモ: サーバー アプリケーションを終了する前に、すべての SQL 接続を必ず閉じてください。 この例では、クライアントの TSQLConnection コンポーネントの Connected プロパティを、False に設定します。 DataSnap では中断している接続に関する警告が表示されません。したがって、サーバーが閉じられているように見える場合でも、サーバーへの接続がなくなるまで、サーバーは終了しません。 すべてのクライアント アプリケーションを閉じても、この問題の解決になりません。 Delphi IDE からサーバーへの接続を自動的に開き、公開されたクラスとメソッドを参照できるからです。