解説

インサイド .NET Framework [改訂版]

第3回 アセンブリのロード

吉松 史彰
2003/07/09

Page1 Page2 Page3 Page4 Page5

■グローバル・アセンブリ・キャッシュ(GAC)

 グローバル・アセンブリ・キャッシュ(GAC)とは、名前のとおりマシン全体でグローバルに参照可能なアセンブリの配置場所だ。.NET Frameworkをインストールすると、デフォルトでは「%Systemroot%\assembly」フォルダ以下がGACとして設定される。GACは特殊なフォルダ構造なので、ここに単純にファイルをコピーするようなことはできない。実際、エクスプローラで「%Systemroot%\assembly」フォルダを見てみると、アセンブリの名前を一覧表示するシェル拡張が起動される。

エクスプローラで表示したグローバル・アセンブリ・キャッシュ(GAC)の内容

 もっとも、コマンド・プロンプトでフォルダをのぞいてみると、GACの内部的なフォルダ構造を見ることができる。

コマンド・プロンプトから表示したGACのフォルダ構造

 GACにアセンブリをインストールするには、2つ方法がある。1つはエクスプローラを使って、GACにファイルをドロップする方法だ。アセンブリのプライマリ・モジュール・ファイルをこのフォルダにドロップするだけで、アセンブリがGACに登録される。もう1つはgacutil.exeツールを利用する方法だ。このツールは、名前のとおりGACの管理を行うツールだ。コマンドライン・ツールなので、コマンド・プロンプトから次のように実行する。

% gacutil -i util.dll

 gacutilコマンドの詳細については、.NET Framework SDKのドキュメントを参照してほしい。

■アセンブリのコードベース

 GACでアセンブリが見つかった場合は、そのアセンブリがそのまま使われる。だが見つからなかった場合は、CLRは次にアプリケーション(本稿の場合はuser.exe)の構成ファイルを調べて、アセンブリのコードベースを参照する。

 アプリケーションの構成ファイルとは、次のようなXML1.0形式のテキスト・ファイルだ。このようなファイルを、「アプリケーションのファイル名.config」という名前で保存したものがアプリケーションの構成ファイルになる。ファイル名は決まっているので勝手に変えることはできない。本稿の場合は「user.exe.config」という名前で保存することになる。なお、XML1.0の制約によって、このファイルはUTF-8エンコーディングで保存することが推奨される。Windowsのメモ帳では保存するときに保存形式を選択できるので、UTF-8を選択すればよい。

プライマリ・モジュールへのパスを記述したアプリケーション構成ファイルの例

 10行目のcodeBase要素に注目してほしい。CLRはアプリケーションの構成ファイルを見つけると、その中で今探しているアセンブリ(この場合はutilアセンブリ)を表すassemblyIdentity要素を持つdependentAssembly要素を探す。見つかったら、dependentAssembly要素の子要素であるcodeBase要素のhref属性に書いてあるパスを取得して、これをアセンブリのプライマリ・モジュールへのパスと解釈する。ここではhref属性に相対パスを指定しているが、dependentAssembly要素に厳密名付きアセンブリの名前が(バージョン以外は)正確に書いてある場合は、絶対パスを使ってアプリケーション(user.exe)が入っているディレクトリとはまったく異なるツリーに存在するディレクトリを、href属性に指定することもできる。

 あいまいな名前のアセンブリの場合は、href属性にはアプリケーションのディレクトリのサブディレクトリを表すパスしか指定できない。サブディレクトリでない場合は、指定は無効で、アセンブリはロードされない。

■プライマリ・モジュールの探索終了

 GAC、またはコードベースからプライマリ・モジュールが見つかった場合、その時点で探索は終了する。GACで見つからず、そのあとcodeBaseを探してもプライマリ・モジュールが見つからなかった場合も、これで探索は終了する。

 アセンブリが見つからなかった場合は、Mainメソッドの1行目(new Util())で“System.IO.FileNotFoundException”が発生することになる。また、codeBase要素のhref属性に指定されたパスからファイルが見つかったものの、そのファイルにマニフェストが見つからなかった場合や、そもそもそのファイルが実行可能ファイルではなかった場合(単なるテキスト・ファイルに.dllという拡張子を付けて保存したものなど)は、“System.IO.FileLoadException”が発生する。さらに、見つかったファイルが実行可能ファイルではあるものの、CLR向けにコンパイルされたものでない場合は、“System.BadImageFormatException”が発生する。

■アセンブリの配置

 GACにアセンブリを配置することを「グローバル配置」と呼ぶ。反対に、アプリケーションの構成ファイルを見ない限り場所が特定できないコードベースにアセンブリを配置することを「プライベート配置」と呼ぶ。厳密名付きアセンブリはグローバルにもプライベートにも配置できるが、あいまいな名前のアセンブリはグローバルに配置することはできない*2

*2 なお、.NET Framework SDKのドキュメントには、「共有アセンブリ」と「プライベート・アセンブリ」という用語があるが、この用語は間違いだ(と筆者は断言する)。アセンブリの種類は2つある。厳密名付きアセンブリとあいまいな名前のアセンブリだ。アセンブリの配置方法は2つある。グローバル配置とプライベート配置だ。この両者はほぼ直交した概念だ。GACに配置したアセンブリとcodeBaseに配置したアセンブリで、中のコードに違いがあるわけではない。単にロード方法が異なるだけだ。筆者は、ロード方法が異なるだけのものにあたかも違うものであるかのような名前を付けてしまうのは間違っていると考えている。

 CLRがアセンブリを探索する場所は、GACとコードベースの2つしかない。それでは、実際にエンド・ユーザーにアプリケーションを配布するときには、GACに配置すべきなのだろうか、それともコードベースを利用すべきなのだろうか。

 筆者の考えをいえば、アセンブリはコードベースを使ってプライベート配置すべきだ。通常のアプリケーション用のアセンブリをGACにインストールする必要はまったくない。本稿を読んでいる開発者の中で、GACにインストールしなければならないアセンブリを開発する開発者は0.01%にも満たないと断言できる。理由は、ユーザーのマシン全体で共有すべきアセンブリを作る理由はほとんどないからだ。

 確かに.NET Frameworkは、オブジェクト指向に基づいた再利用可能なコンポーネントの活用を基礎とする開発環境だ。だが、世の中の99.99%以上の開発者は、Microsoftやほかのごく一握りのベンダが開発したコンポーネントを利用するだけだ。であれば、自分がいま開発しているアプリケーション(本稿ではuser.exe)から利用するためのアセンブリ(本稿ではutil.dll)をGACに登録しても、結局そのアセンブリを使うのは自分のアプリケーションだけなのだ。ほかの開発者から利用してもらうアセンブリ(コンポーネント)を開発、販売しているベンダならともかく、エンド・ユーザーに使ってもらうアプリケーションを開発している場合は、そのアセンブリをGACに登録する必要などさらさらない。従って、ほとんどの場合GACにアセンブリを登録するのはまったく無意味だ。

 アセンブリをGACに配置する場合は、アプリケーションのインストール時にGACに登録するという作業が別途発生することも忘れてはならない。GACに配置することにしたら、.NET Frameworkのウリの1つである「コピーしただけでインストール完了」というキャッチフレーズはウソになる。GACに登録するという作業は、レジストリにCOM DLLを登録する作業と何の違いもない。一方で「レジストリが必要なくなりました」といっておきながら、一方で「登録作業が必要です」などというのははっきりいってサギだ。GACはレジストリと本質的に何も変わらない。構成ファイルを使ってコードベースでアセンブリを指定すれば、文字どおりアセンブリはコピーしただけで機能するようになるのだ。


 INDEX
  解説 インサイド .NET Framework [改訂版]
  第3回 アセンブリのロード
    1.はじめにサンプル・アプリケーション
    2.アセンブリのロード 1〜2段階
  3.GACとコードベース
    4.アセンブリのロード 3〜5段階
    5.アセンブリの配置に関する補足とまとめ
 
インデックス・ページヘ  「解説:インサイド .NET Framework [改訂版]」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間