サービスコンポーネントのさまざまな配置方法(後編)
System.EnterpriseServices.RegistrationHelperクラスを使って配置を自動化する
これらの手動の配置方法は、サイズが小さいアプリケーションにしか利用できません。例えば、ターゲットサーバーにインストールするために複雑なインストールプログラムを必要とする、エンタープライズアプリケーション内でサービスコンポーネントを使用する場合は、そのサービスコンポーネントの配置を、インストールプログラムの一部として行う必要があります。また、アセンブリをGACにインストールする処理をインストールプログラムの一部として行うことが必要になる場合もあります。このようなインストールを実行するスクリプトやバッチファイルを作成することもできますが、もっと簡単な方法があります。Visual Studio .NET のセットアップ/配置プロジェクトを使用すると、コンポーネント登録用のコードを呼び出す機能や、インストール時またはアンインストール時にその他の必要な処理を実行する機能を備えたセットアッププロジェクトを簡単に作成できます。このためには、インストール時またはアンインストール時に実行するカスタム動作を作成する必要があります。カスタム動作を作成するために必要な作業は、System.Configuration.Install.Installerを継承するクラスをアセンブリ内で作成し、配置プロジェクトにカスタムのインストール動作を追加することだけです。今回の例では、先ほど作成したLibraryAppサービスコンポーネントを使うことにします。
LibraryAppサービスコンポーネントアセンブリにインストーラクラスを追加するには、次のようにします。
- LibraryAppプロジェクトを右クリックします。
- [Add / New Item...]を選択し、[Add New Item]ダイアログボックスを表示します。
- [Categories]ペインで[Code]を選択します。
- [Templates]ペインで[Installer Class]を選択し、クラスの名前としてCustomActionInstallerを指定します。
クラスを作成できたら、そのクラスにInstallメソッドとUninstallメソッドを追加します。
public override void Install( System.Collections.IDictionary stateSaver) { try { string appID = null; string typeLib = null; // Get the location of the current assembly string assembly = GetType().Assembly.Location; // Install the application RegistrationHelper regHelper = new RegistrationHelper (); regHelper.InstallAssembly (assembly, ref appID, ref typeLib, InstallationFlags.FindOrCreateTargetApplication); // Save the state - you will need this for the uninstall stateSaver.Add ("AppID", appID); stateSaver.Add ("Assembly", assembly); } catch(Exception ex) { #if DEBUG Debug.WriteLine (ex); #endif StreamWriter writer = File.AppendText ("InstallError.log"); writer.WriteLine ("Uninstall Error: {0}", ex.Message); // If the installer catches the exception it will display // an error message. Show a friendly error message throw new ApplicationException ( "Error installing the middle tier", ex); } } public override void Uninstall( System.Collections.IDictionary savedState) { try { // Get the state created when the app was installed string appID = (string)savedState["AppID"]; string assembly = (string)savedState["Assembly"]; // Uninstall the application RegistrationHelper regHelper = new RegistrationHelper (); regHelper.UninstallAssembly (assembly, appID); } catch ( Exception ex) { // Don't allow unhandled exceptions during uninstall #if DEBUG Debug.WriteLine (ex); #endif StreamWriter sw = File.AppendText ("InstallError.log"); sw.WriteLine ("Uninstall Error: {0}", ex.Message); } }
このコード行について詳しく説明しましょう。まず、現在使用しているアセンブリの場所の参照を取得します。
string assembly = GetType().Assembly.Location;
ここで、RegistrationHelperクラスのインスタンスを作成します。
RegistrationHelper regHelper = new RegistrationHelper ();
その後、InstallAssemblyメソッドを呼び出してアセンブリをインストールし、appID変数とtypeLib変数をbyref引数として渡します。アセンブリをインストールしたら、新たに作成したアプリケーションのIDの参照と、ローカル変数に代入されているタイプライブラリを取得します。
regHelper.InstallAssembly (assembly, ref appID, ref typeLib, InstallationFlags.FindOrCreateTargetApplication);
次に、用意されているコレクションオブジェクトにAppIDとアセンブリの場所を保存し、後で取得できるようにしておきます。永続化した情報はアプリケーションのアンインストールフェーズで使います。
stateSaver.Add ("AppID", appID);
stateSaver.Add ("Assembly", assembly);
}
このコード行の実行時に例外が発生した場合は、その例外をキャッチし、例外情報をログファイル「InstallError.log」に書き込みます。
catch(Exception ex)
{
#if DEBUG
Debug.WriteLine (ex);
#endif
StreamWriter writer = File.AppendText ("InstallError.log");
writer.WriteLine ("Uninstall Error: {0}", ex.Message);
// If the installer catches the exception it will display
// an error message. Show a friendly error message
throw new ApplicationException
(
"Error installing the middle tier", ex);
}
}
Uninstallメソッドでは、まずコレクションオブジェクトからAppIDとアセンブリ情報を取得します。
// Get the state created when the app was installed string appID = (string)savedState["AppID"]; string assembly = (string)savedState["Assembly"];
次に、RegistrationHelperクラスのUninstallAssemblyメソッドを呼び出してアセンブリをアンインストールします。
RegistrationHelper regHelper = new RegistrationHelper ();
regHelper.UninstallAssembly (assembly, appID);
}
ここで再び、例外ブロックで、例外情報を外部のログファイル「InstallError.log」に書き込みます。
catch ( Exception ex)
{
// Don't allow unhandled exceptions during uninstall
#if DEBUG
Debug.WriteLine (ex);
#endif
StreamWriter sw = File.AppendText ("InstallError.log");
sw.WriteLine ("Uninstall Error: {0}", ex.Message);
}
}
インストーラクラスを作成できたら、CustomInstallerクラスのInstallメソッドとUninstallメソッドが自動的に呼び出されるように、配置プロジェクトにカスタム動作を追加します。その前に、既存のLibraryAppソリューションに新しい配置プロジェクトを追加する必要があります。このため、次のように「LibraryAppSetup」という新しいプロジェクトを作成します。
次に、配置プロジェクトにLibraryAppプロジェクトの出力を追加する必要があります。このためには、LibraryAppSetupプロジェクトを右クリックし、[Add]をポイントして[Project Output]を選択します。[Add Project Output Group]ダイアログボックスの[project]ドロップダウンボックスから[LibraryApp]を選択し、出力リストから[Primary Output]を選択します。次に、インストーラがCustomActionInstallerクラスのInstallメソッドとUninstallメソッドを呼び出すように、配置プロジェクトにカスタム動作を追加する必要があります。
カスタム動作を追加する
カスタム動作はインストールのさまざまなフェーズで呼び出すことができます。インストールが終了した後またはロールバックされた後は、コミットフェーズとロールバックフェーズが発生します。コミットフェーズとロールバックフェーズの際に重要な作業を実行してはなりません。Installメソッドはインストールフェーズで呼び出し、Uninstallメソッドはアンインストールフェーズで呼び出します。
カスタム動作を追加するには、次のようにします。
- LibraryAppSetupプロジェクトを右クリックし、[View]をポイントして[File System]を選択します。
- [Install]フェーズを右クリックし、[Add Custom Action...]を選択します。
- ターゲットコンピュータのファイルシステムをナビゲートし、カスタム動作クラスが入っているLibraryAppアセンブリを探します。
GACにアセンブリを配置する
インストールの一部として、GACにサービスコンポーネントを配置することもできます。これは、COM+サーバーアプリケーションにサービスコンポーネントを配置する場合に非常に便利です。GACにサービスコンポーネントをインストールするには、次の操作を実行します。
- LibraryAppSetupプロジェクトを右クリックし、[View]をポイントして[File System]を選択します。
- 既定では、フォルダのリストにグローバルアセンブリキャッシュフォルダは表示されません。リストにグローバルアセンブリキャッシュフォルダを追加するには、[File System on Target Machin]を右クリックし、[Add Special Folder]をポイントして[Global Assembly Folder]を選択します。
- グローバルアセンブリフォルダを右クリックし、[Add]をポイントして[Assembly]を選択し、GACフォルダにアセンブリを追加します。
これで、インストーラを作成して「LibraryAppSetup.msi」ファイルを実行すると、アセンブリがコンポーネントサービスに登録されているだけでなく、GACにも配置されていることが分かります。
XCOPY配置とサービスコンポーネント
.NET Frameworkの目標の1つは、XCOPY配置をサポートすることによってシステムのインストールを簡略化することです。XCOPYとは、ファイルやディレクトリを別の場所にコピーするためのMS-DOSコマンドラインユーティリティのことです。XCOPY配置の目的は、コードを実行することなくアプリケーションをリモートサーバーにインストールできるようにすることです。XCOPY配置をサポートするために、CLR/COM+の統合アーキテクチャでは、インストール時に「regsvcs.exe」の実行を無視し、サービスコンポーネントが初めて使用されるときに自動登録を行うような仕組みが用意されています。これを「レイジー登録」と言います。レイジー登録は、ライブラリアプリケーションにサービスコンポーネントを配置する場合に役立ちます。ただし、XCOPY配置にも注意しなければならない欠点があります。
- COM+システムアプリケーションで定義されている管理者ロールに含まれるユーザーしかCOM+カタログを更新できません。既定の管理者ロールにはローカルの管理者しか含まれていません。そのため、サービスコンポーネントを正しく登録するには、最初にサービスコンポーネントを使うコードに管理者特権を付与する必要があります。そうしないと、登録は失敗します。
- GACにサービスコンポーネントを配置する場合は適切なディレクトリにファイルをコピーすれば簡単に配置できますが、サーバーアプリケーションにもアセンブリを配置する場合には別の作業が必要になります。特に、メタデータでは自動的に設定されない、COM+サーバーアプリケーションのセキュリティプリンシパルの設定が必要になります。COM+ライブラリアプリケーションに設定済みクラスを配置する場合は、アセンブリがクライアントのプライベートディレクトリに配置されている限り問題ありません。
GACにサービスコンポーネントをインストールすることが必要な場合
次の条件に当てはまる場合は、GACにサービスコンポーネントをインストールすることが必要です。
- アプリケーションがSOAP(クライアントとサーバーの両方)または.NET Remotingを使っている場合。
- マネージドコードからサービスコンポーネントにアクセスし、かつアセンブリの格納ディレクトリが実行可能ファイルとは異なる場合。つまり、マネージドコードからアセンブリを探す場合、アセンブリは、アプリケーションディレクトリ内にないときはGAC内になければなりません。
- 同じコンピュータ上のすべてのクライアントアプリケーションが同じアセンブリを共有する場合。
- サービスコンポーネントがCOM+サーバーアプリケーションに配置されている場合。COM+ライブラリアプリケーションに配置されているサービスコンポーネントは、ディレクトリが別々でない限り、GACに置く必要はありません。現在ログオンしているユーザーは管理者グループに含まれていなければなりません。
まとめ
この記事では、.NET Frameworkに用意されているさまざまなクラスやツールを使ってサービスコンポーネントを配置する方法を説明しました。また、Windowsインストーラテクノロジを利用すると、サービスコンポーネントの配置を自動化するWindowsインストーラプロジェクトを簡単に作成できることも説明しました。
最後に、この記事を読んでくださった方に感謝します。また、この記事があなたにとって有益であることを願っています。

