チュートリアル:アプリケーションで DataSnap サーバーを使用する
チュートリアル への移動
DataSnap 技術により、インターネット、ローカル ネットワークまたはローカル ホスト内を通信する、クライアントサーバー型アプリケーションを作成できます。
次のサンプルでは、簡単なローカルのクライアントサーバー型アプリケーションを作成するときの DataSnap の使用方法について示します。クライアント アプリケーションとサーバー アプリケーションの両方とも Delphi で実装されています。サーバーを作成し、クライアントとサーバー間の接続を DataSnap でアクティブにした後に、サーバーで定義され、実装されているメソッドを、クライアントが呼び出すことができます。
サーバーは Delphi と C++ のいずれでも実装できます。この例では両方を示します。クライアントを同じ言語で実装する必要はありません。DataSnap では、Delphi でサーバーを、C++ でクライアントを実装することも、その逆の組み合わせにすることも可能です。
目次 |
DataSnap サーバーの主要コンポーネント
主なコンポーネントは以下のとおりです。
TDSServer コンポーネントは DataSnap サーバー アプリケーションの中心ロジックです。これには、サーバーを開始する Start メソッド、および停止する Stop メソッドが含まれます。AutoStart プロパティもあります。デフォルトでは、AutoStart の値は True に設定され、アプリケーションの起動時に、サーバーが自動的に起動します。1 つのサーバー アプリケーションに必要なのは、1 つの TDSServer コンポーネントだけです。
TDSServerClass コンポーネントはサーバー クラスを表します。
DataSnap サーバーはサーバー クラスのインスタンスを自動的に作成し、破棄します。サーバー クラスのインスタンス化は、LifeCycle プロパティ(TDSServerClass コンポーネント)で制御します。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]をメイン メニューからクリックします。
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"
- クライアント アプリケーションから呼び出すクラスを指定するには、OnGetClass イベントを TDSServerClass コンポーネントに対して定義します。MyServer の[デザイン]タブで次のとおり実行します。
- TDSServerClass コンポーネントをフォーム上で選択します。
- [イベント]タブを[オブジェクト インスペクタ]で選択します。
- [OnGetClass]イベントの値をダブルクリックします。
- ちょうど生成された関数で、
PersistentClassを設定する、1 行のコードを追加します。 - このイベントを実装しないと、起動直後に、アプリケーションから、次のメッセージとともに TDBXError 例外が発生します。
- OnGetClass イベントが設定されていないか、クラス参照がありません
- OnGetClass イベントには参照渡しの
PersistentClass引数があります。イベント ハンドラのコードで、開発者はPersistentClassにサーバー クラスへのクラス参照を割り当てる必要があります(前のサンプルを参照)。 - これが DataSnap アーキテクチャを理解するために必要な重要概念です。クラス参照が
PersistentClassに割り当てられます。オブジェクト参照ではありません。
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); }
これでサーバー アプリケーションの実装は完了です。
クライアント アプリケーションの作成
- クライアント アプリケーションをサーバー アプリケーションと同じプロジェクト グループで作成するには、[プロジェクト マネージャ]のプロジェクト グループ名を右クリックして、[新規プロジェクトの追加...]を選択するか、[プロジェクト|新規プロジェクトを追加...]をメイン メニューから選択します。[新規作成]ダイアログ ボックスが開きます。
- 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 の先頭に追加します。
- クライアント アプリケーションで必要なメソッドを呼び出します。この例では、TButton コンポーネントの OnClick イベントを実装し、自動的に生成された DataSnap クライアント ユニットの Sum メソッドを呼び出します。ここで、生成クラスは
TMyClassClientであり、ボタンのイベント ハンドラはTClientForm.CalculateClick(Delphi)またはTClientForm::Button1Click(C++)です。 - 最後に、クライアント アプリケーションをビルドし実行します。クライアント フォームが表示されます。[A]と[B]の各フィールドに 10 進数を入力し、[Calculate]ボタンをクリックします。合計が[Result]フィールドに表示されます。
- 接続に nil を指定できません。接続が開いていることを確認してください。
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; } }
次のエラー メッセージが表示された場合は、
TSQLConnection コンポーネントの Connected プロパティが true に設定されていない可能性があります。
メモ: サーバー アプリケーションを終了する前に、すべての SQL 接続を必ず閉じてください。この例では、クライアントの TSQLConnection コンポーネントの Connected プロパティを false に設定します。DataSnap では中断している接続に関する警告が表示されません。したがって、サーバーが閉じられているように見える場合でも、サーバーへの接続がなくなるまで、サーバーは終了しません。すべてのクライアント アプリケーションを閉じても、この問題の解決になりません。Delphi IDE からサーバーへの接続を自動的に開き、公開されたクラスとメソッドを参照できるからです。


