次の方法で共有


ランタイムがアセンブリを検索する方法

この記事は .NET Framework に固有のものです。 .NET 6 以降のバージョンを含む、.NET の新しい実装には適用されません。

.NET Framework アプリケーションを正常にデプロイするには、共通言語ランタイムがアプリケーションを構成するアセンブリを見つけてバインドする方法を理解する必要があります。 既定では、ランタイムは、アプリケーションがビルドされたアセンブリの正確なバージョンとのバインドを試みます。 この既定の動作は、構成ファイルの設定によってオーバーライドできます。

共通言語ランタイムは、アセンブリを検索してアセンブリ参照を解決しようとするときに、いくつかの手順を実行します。 各手順については、次のセクションで説明します。 プローブという用語は、ランタイムがアセンブリを検索する方法を記述するときによく使用されます。名前とカルチャに基づいてアセンブリを検索するために使用されるヒューリスティックのセットを参照します。

Windows SDK に含まれている アセンブリ バインド ログ ビューアー (Fuslogvw.exe) を使用して、ログ ファイル内のバインド情報を表示できます。

バインドの開始

アセンブリを検索してバインドするプロセスは、ランタイムが別のアセンブリへの参照を解決しようとしたときに開始されます。 この参照には、静的または動的のいずれかを指定できます。 コンパイラは、ビルド時にアセンブリ マニフェストのメタデータに静的参照を記録します。 動的参照は、 Assembly.Loadなどのさまざまなメソッドを呼び出した結果として、その場で構築されます。

アセンブリを参照する推奨される方法は、アセンブリ名、バージョン、カルチャ、公開キー トークン (存在する場合) を含む完全な参照を使用することです。 ランタイムは、このセクションで後述する手順に従って、この情報を使用してアセンブリを検索します。 ランタイムは、参照が静的アセンブリ用か動的アセンブリ用かに関係なく、同じ解決プロセスを使用します。

アセンブリ名のみを指定するなど、アセンブリに関する部分的な情報のみを呼び出し元のメソッドに提供することで、アセンブリへの動的参照を行うこともできます。 この場合、アプリケーション ディレクトリのみがアセンブリを検索し、他のチェックは行われません。 Assembly.LoadAppDomain.Loadなどのアセンブリを読み込むには、さまざまな方法のいずれかを使用して部分参照を行います。

最後に、 Assembly.Load などのメソッドを使用して動的参照を作成し、部分的な情報のみを指定できます。その後、アプリケーション構成ファイルの <qualifyAssembly> 要素を使用して参照を修飾します。 この要素を使用すると、コードではなく、アプリケーション構成ファイルに完全な参照情報 (名前、バージョン、カルチャ、および該当する場合は公開キー トークン) を指定できます。 この手法は、アプリケーション ディレクトリの外部にあるアセンブリへの参照を完全に修飾する場合、またはグローバル アセンブリ キャッシュ内のアセンブリを参照する必要があるが、コードではなく構成ファイルで完全な参照を指定する利便性が必要な場合に使用します。

この種類の部分参照は、複数のアプリケーション間で共有されるアセンブリでは使用しないでください。 構成設定はアプリケーションごとに適用され、アセンブリごとに適用されないため、この種類の部分参照を使用する共有アセンブリでは、共有アセンブリを使用する各アプリケーションがその構成ファイルに修飾情報を含める必要があります。

ランタイムは、次の手順を使用してアセンブリ参照を解決します。

  1. アプリケーション構成ファイル、発行元ポリシー ファイル、コンピューター構成ファイルなど、該当する構成ファイルを調べることで、適切なアセンブリ のバージョンを確認します。 構成ファイルがリモート コンピューター上にある場合、ランタイムは最初にアプリケーション構成ファイルを見つけてダウンロードする必要があります。

  2. アセンブリ名が以前にバインドされているかどうかを確認 し、バインドされている場合は、以前に読み込まれたアセンブリを使用します。 アセンブリを読み込む前の要求が失敗した場合、要求はすぐに失敗し、アセンブリを読み込もうとしません。

    アセンブリ バインドエラーのキャッシュは、.NET Framework バージョン 2.0 の新機能です。

  3. グローバル アセンブリ キャッシュを確認します。 アセンブリが見つかった場合、ランタイムはこのアセンブリを使用します。

  4. の手順を使用してアセンブリのプローブを実行します。

    1. 構成と発行元のポリシーが元の参照に影響を与えない場合、およびバインド要求が Assembly.LoadFrom メソッドを使用して作成された場合、ランタイムは場所のヒントをチェックします。

    2. 構成ファイルにコードベースが見つかった場合、ランタイムはこの場所のみをチェックします。 このプローブが失敗した場合、ランタイムはバインディング要求が失敗し、他のプローブは発生しないと判断します。

    3. プローブセクションで説明されているヒューリスティックを使用したアセンブリのプローブ。 プローブ後にアセンブリが見つからない場合、ランタイムは、アセンブリを提供するように Windows インストーラーに要求します。 これは、オンデマンドインストール機能として機能します。

      厳密な名前を持たないアセンブリのバージョン チェックも、厳密な名前を持たないアセンブリのグローバル アセンブリ キャッシュのランタイム チェックもありません。

手順 1: 構成ファイルを調べる

アセンブリ バインド動作は、次の 3 つの XML ファイルに基づいて異なるレベルで構成できます。

  • アプリケーション構成ファイル。

  • 発行元ポリシー ファイル。

  • マシン構成ファイル。

これらのファイルは同じ構文に従い、バインド リダイレクト、コードの場所、特定のアセンブリのバインド モードなどの情報を提供します。 各構成ファイルには、バインド プロセスをリダイレクトする <assemblyBinding> 要素を含めることができます。 <assemblyBinding> 要素の子要素には、<dependentAssembly> 要素が含まれます。 <dependentAssembly> 要素の子には、<assemblyIdentity> 要素、<bindingRedirect> 要素および <codeBase> 要素が含まれます。

構成情報は、3 つの構成ファイルにあります。すべての要素がすべての構成ファイルで有効なわけではありません。 たとえば、バインド モードとプライベート パスの情報は、アプリケーション構成ファイルにのみ含めることができます。 各ファイルに含まれる情報の完全な一覧については、「構成ファイルを 使用したアプリの構成」を参照してください。

アプリケーション構成ファイル

最初に、共通言語ランタイムは、呼び出し元アセンブリのマニフェストに格納されているバージョン情報をオーバーライドする情報について、アプリケーション構成ファイルをチェックします。 アプリケーション構成ファイルはアプリケーションと共にデプロイできますが、アプリケーションの実行には必要ありません。 通常、このファイルの取得はほぼ瞬時に行われますが、Web ベースのシナリオなど、リモート コンピューター上にアプリケーション ベースがある場合は、構成ファイルをダウンロードする必要があります。

クライアント実行可能ファイルの場合、アプリケーション構成ファイルはアプリケーションの実行可能ファイルと同じディレクトリに存在し、.config 拡張子を持つ実行可能ファイルと同じベース名を持ちます。 たとえば、C:\Program Files\Myapp\Myapp.exe の構成ファイルは C:\Program Files\Myapp\Myapp.exe.config。ブラウザーベースのシナリオでは、HTML ファイルで <link> 要素を使用して構成ファイルを明示的にポイントする必要があります。

次のコードは、アプリケーション構成ファイルの簡単な例を示しています。 次の使用例は、Listeners コレクションにTextWriterTraceListenerを追加して、デバッグ情報をファイルに記録できるようにします。

<configuration>
   <system.diagnostics>
      <trace useGlobalLock="false" autoflush="true" indentsize="0">
         <listeners>
            <add name="myListener" type="System.Diagnostics.TextWriterTraceListener, system version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" initializeData="c:\myListener.log" />
         </listeners>
      </trace>
   </system.diagnostics>
</configuration>

パブリッシャー ポリシー ファイル

2 つ目は、発行者ポリシー ファイルが存在する場合に、ランタイムによって検証されます。 パブリッシャー ポリシー ファイルは、コンポーネントパブリッシャーによって修正プログラムとして配布されるか、共有コンポーネントに更新されます。 これらのファイルには、アセンブリ参照を新しいバージョンに転送する共有コンポーネントの発行元によって発行された互換性情報が含まれています。 アプリケーションおよびマシン構成ファイルとは異なり、パブリッシャー ポリシー ファイルは、グローバル アセンブリ キャッシュにインストールする必要がある独自のアセンブリに含まれています。

パブリッシャー ポリシー構成ファイルの例を次に示します。

<configuration>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

            <dependentAssembly>
                <assemblyIdentity name="asm6" publicKeyToken="c0305c36380ba429" />
                <bindingRedirect oldVersion="3.0.0.0" newVersion="2.0.0.0"/>
            </dependentAssembly>

        </assemblyBinding>
    </runtime>
</configuration>

アセンブリを作成するには、次のようなコマンドで Al.exe (アセンブリ リンカー) ツールを使用できます。

Al.exe /link:asm6.exe.config /out:policy.3.0.asm6.dll /keyfile: compatkey.dat /v:3.0.0.0

compatkey.dat は厳密な名前のキー ファイルです。 このコマンドを実行すると、グローバル アセンブリ キャッシュに配置できる厳密な名前のアセンブリが作成されます。

パブリッシャー ポリシーは、共有コンポーネントを使用するすべてのアプリケーションに影響します。

発行元ポリシー構成ファイルは、アプリケーション (つまり、アセンブリ マニフェストまたはアプリケーション構成ファイル) から取得されたバージョン情報をオーバーライドします。 アセンブリ マニフェストで指定されたバージョンをリダイレクトするステートメントがアプリケーション構成ファイルに存在しない場合は、アセンブリ マニフェストで指定されたバージョンがパブリッシャー ポリシー ファイルによってオーバーライドされます。 ただし、アプリケーション構成ファイルにリダイレクト ステートメントがある場合は、マニフェストで指定されたバージョンではなく、パブリッシャー ポリシーによってそのバージョンがオーバーライドされます。

共有コンポーネントが更新され、そのコンポーネントを使用するすべてのアプリケーションが新しいバージョンの共有コンポーネントを取得する必要がある場合は、発行者ポリシー ファイルが使用されます。 発行元ポリシー ファイルの設定は、アプリケーション構成ファイルがセーフ モードを適用しない限り、アプリケーション構成ファイルの設定をオーバーライドします。

セーフモード

通常、パブリッシャー ポリシー ファイルは、Service Pack またはプログラムの更新プログラムの一部として明示的にインストールされます。 アップグレードされた共有コンポーネントに問題がある場合は、安全モードを使用してパブリッシャー ポリシー ファイルのオーバーライドを無視できます。 セーフ モードは、アプリケーション構成ファイルにのみ存在する <publisherPolicy apply="yes|no"/> 要素によって決まります。 バインド プロセスからパブリッシャー ポリシー構成情報を削除するかどうかを指定します。

セーフ モードは、アプリケーション全体または選択したアセンブリに対して設定できます。 つまり、アプリケーションを構成するすべてのアセンブリのポリシーをオフにしたり、一部のアセンブリでは有効にできますが、他のアセンブリでは有効にすることはできません。 アプリケーションを構成するアセンブリにパブリッシャー ポリシーを選択的に適用するには、 <publisherPolicy apply=no/> を設定し、 <dependentAssembly> 要素を使用して影響を受けるアセンブリを指定します。 アプリケーションを構成するすべてのアセンブリに発行元ポリシーを適用するには、<publisherPolicy apply=no/> に依存アセンブリ要素を設定します。 構成の詳細については、「構成 ファイルを使用したアプリの構成」を参照してください。

マシン構成ファイル

3 番目に、ランタイムはマシン構成ファイルを調べます。 Machine.configと呼ばれるこのファイルは、ランタイムがインストールされているルート ディレクトリの Config サブディレクトリ内のローカル コンピューターに存在します。 このファイルは、管理者が、そのコンピューターに対してローカルなアセンブリ バインド制限を指定するために使用できます。 マシン構成ファイルの設定は、他のすべての構成設定よりも優先されます。ただし、これは、すべての構成設定をこのファイルに配置する必要があることを意味するわけではありません。 管理者ポリシー ファイルによって決定されるバージョンは最終版であり、オーバーライドできません。 Machine.config ファイルで指定されたオーバーライドは、すべてのアプリケーションに影響します。 構成ファイルの詳細については、「構成ファイル を使用したアプリの構成」を参照してください。

手順 2: 以前に参照されたアセンブリを確認する

要求されたアセンブリが以前の呼び出しでも要求されている場合、共通言語ランタイムは既に読み込まれているアセンブリを使用します。 これは、アプリケーションを構成するアセンブリに名前を付けるときに影響を受ける可能性があります。 アセンブリの名前付けの詳細については、「 アセンブリ名」を参照してください。

アセンブリに対する以前の要求が失敗した場合、アセンブリの後続の要求は、アセンブリの読み込みを試みることなくすぐに失敗します。 .NET Framework バージョン 2.0 以降では、アセンブリ バインドエラーがキャッシュされ、キャッシュされた情報を使用してアセンブリの読み込みを試みるかどうかを判断します。

バインドエラーをキャッシュしなかった .NET Framework バージョン 1.0 および 1.1 の動作に戻すには、構成ファイルに <disableCachingBindingFailures> 要素 を含めます。

手順 3: グローバル アセンブリ キャッシュの確認

厳密な名前のアセンブリの場合、バインド プロセスはグローバル アセンブリ キャッシュを調べることで続行されます。 グローバル アセンブリ キャッシュには、コンピューター上の複数のアプリケーションで使用できるアセンブリが格納されます。 グローバル アセンブリ キャッシュ内のすべてのアセンブリには厳密な名前が必要です。

手順 4: コードベースまたはプローブを使用してアセンブリを検索する

呼び出し元アセンブリの参照と構成ファイルの情報を使用して適切なアセンブリ バージョンが決定された後、グローバル アセンブリ キャッシュ (厳密な名前付きアセンブリの場合のみ) でチェックされた後、共通言語ランタイムはアセンブリの検索を試みます。 アセンブリを検索するプロセスには、次の手順が含まれます。

  1. アプリケーション構成ファイルに <codeBase> 要素が見つかった場合、ランタイムは指定された場所を確認します。 一致するものが見つかった場合、そのアセンブリが使用され、プローブは行われません。 アセンブリが見つからない場合、バインド要求は失敗します。

  2. ランタイムは、このセクションで後述する規則を使用して、参照先アセンブリをプローブします。

1 つのディレクトリに複数のバージョンのアセンブリがあり、そのアセンブリの特定のバージョンを参照する場合は、<probing> 要素のprivatePath属性ではなく、<codeBase> 要素を使用する必要があります。 <probing> 要素を使用する場合、ランタイムは、参照されている単純なアセンブリ名と一致するアセンブリが初めて見つかると、それが正しい一致であるかどうかに関係なく、プローブを停止します。 正しい一致である場合は、そのアセンブリが使用されます。 正しい一致ではない場合、プローブは停止し、バインドは失敗します。

Codebase を使用したアセンブリの検索

コードベース情報は、構成ファイル内の <codeBase> 要素を使用して提供できます。 ランタイムが参照先アセンブリのプローブを試みる前に、このコードベースは常にチェックされます。 最終バージョンのリダイレクトを含むパブリッシャー ポリシー ファイルにも <codeBase> 要素が含まれている場合、その <codeBase> 要素が使用されます。 たとえば、アプリケーション構成ファイルで <codeBase> 要素を指定し、アプリケーション情報をオーバーライドするパブリッシャー ポリシー ファイルで <codeBase> 要素も指定している場合、パブリッシャー ポリシー ファイルの <codeBase> 要素が使用されます。

<codeBase> 要素で指定された場所に一致するものが見つからない場合、バインド要求は失敗し、それ以上の手順は実行されません。 ランタイムは、アセンブリが呼び出し元のアセンブリの基準と一致すると判断した場合、そのアセンブリを使用します。 指定された <codeBase> 要素によって指定されたファイルが読み込まれると、ランタイムは、名前、バージョン、カルチャ、および公開キーが呼び出し元のアセンブリの参照と一致することを確認します。

アプリケーションのルート ディレクトリの外部で参照されるアセンブリには厳密な名前が必要であり、グローバル アセンブリ キャッシュにインストールするか、<codeBase> 要素を使用して指定する必要があります。

プローブによるアセンブリの検索

アプリケーション構成ファイルに <codeBase> 要素がない場合、ランタイムは次の 4 つの条件を使用してアセンブリをプローブします。

  • アプリケーション ベース。これは、アプリケーションが実行されているルートの場所です。

  • 参照されるアセンブリのカルチャ属性であるカルチャ。

  • 名前。参照されるアセンブリの名前です。

  • <probing> 要素のprivatePath属性。ルートの場所にあるサブディレクトリのユーザー定義リストです。 この場所は、アプリケーション構成ファイルとマネージド コードで、アプリケーション ドメインの AppDomainSetup.PrivateBinPath プロパティを使用して指定できます。 マネージド コードで指定すると、まずマネージド コード privatePath がプローブされ、その後にアプリケーション構成ファイルで指定されたパスがプローブされます。

アプリケーション ベースディレクトリとカルチャ ディレクトリのプローブ

ランタイムは、常にアプリケーションのベース (コンピューター上の URL またはアプリケーションのルート ディレクトリ) でプローブを開始します。 参照されるアセンブリがアプリケーション ベースで見つからず、カルチャ情報が指定されていない場合、ランタイムはアセンブリ名を持つサブディレクトリを検索します。 プローブされるディレクトリは次のとおりです。

  • [アプリケーション ベース] / [アセンブリ名].dll

  • [アプリケーション ベース] / [アセンブリ名] / [アセンブリ名].dll

参照されるアセンブリにカルチャ情報が指定されている場合は、次のディレクトリのみがプローブされます。

  • [アプリケーション ベース] / [カルチャ] / [アセンブリ名].dll

  • [アプリケーション ベース] / [カルチャ] / [アセンブリ名] / [アセンブリ名].dll

privatePath 属性を使用したプローブ

ランタイムは、参照先アセンブリに対して指定されたカルチャ サブディレクトリとサブディレクトリに加えて、<probing> 要素のprivatePath属性を使用して指定されたディレクトリもプローブします。 privatePath属性を使用して指定するディレクトリは、アプリケーションのルート ディレクトリのサブディレクトリである必要があります。 プローブされるディレクトリは、参照されるアセンブリ要求にカルチャ情報が含まれているかどうかによって異なります。

ランタイムは、参照されている単純なアセンブリ名と一致するアセンブリが初めて見つかると、それが正しい一致であるかどうかに関係なく、プローブを停止します。 正しい一致である場合は、そのアセンブリが使用されます。 正しい一致ではない場合、プローブは停止し、バインドは失敗します。

カルチャが含まれている場合は、次のディレクトリがプローブされます。

  • [アプリケーション ベース] / [binpath] / [culture] / [アセンブリ名].dll

  • [アプリケーション ベース] / [binpath] / [culture] / [アセンブリ名] / [アセンブリ名].dll

カルチャ情報が含まれていない場合は、次のディレクトリがプローブされます。

  • [アプリケーション ベース] / [binpath] / [アセンブリ名].dll

  • [アプリケーション ベース] / [binpath] / [アセンブリ名] / [アセンブリ名].dll

プローブの例

次の情報を指定します。

  • 参照されるアセンブリ名: myAssembly

  • アプリケーション ルート ディレクトリ: http://www.code.microsoft.com

  • 構成ファイルの<probing>要素は、bin を指定します。

  • カルチャ: de

ランタイムは、次の URL をプローブします。

  • http://www.code.microsoft.com/de/myAssembly.dll

  • http://www.code.microsoft.com/de/myAssembly/myAssembly.dll

  • http://www.code.microsoft.com/bin/de/myAssembly.dll

  • http://www.code.microsoft.com/bin/de/myAssembly/myAssembly.dll

同じ名前の複数のアセンブリ

次の例は、同じ名前で複数のアセンブリを構成する方法を示しています。

<dependentAssembly>
   <assemblyIdentity name="Server" publicKeyToken="c0305c36380ba429" />
   <codeBase version="1.0.0.0" href="v1/Server.dll" />
   <codeBase version="2.0.0.0" href="v2/Server.dll" />
</dependentAssembly>

プローブされたその他の場所

アセンブリの場所は、現在のバインディング コンテキストを使用して決定することもできます。 これは、ほとんどの場合、 Assembly.LoadFrom メソッドが使用され、COM 相互運用シナリオで発生します。 アセンブリが LoadFrom メソッドを使用して別のアセンブリを参照する場合、呼び出し元のアセンブリの場所は、参照先アセンブリを検索する場所に関するヒントと見なされます。 一致が見つかった場合、そのアセンブリが読み込まれます。 一致するものが見つからない場合、ランタイムは検索セマンティクスを続行し、Windows インストーラーにクエリを実行してアセンブリを提供します。 バインド要求に一致するアセンブリが指定されていない場合は、例外がスローされます。 この例外は、型が参照された場合はマネージド コードの TypeLoadException 、読み込まれているアセンブリが見つからなかった場合は FileNotFoundException です。

たとえば、Assembly1 参照 Assembly2 と Assembly1 が http://www.code.microsoft.com/utilsからダウンロードされた場合、その場所は、Assembly2.dllを検索する場所に関するヒントと見なされます。 その後、ランタイムは、 http://www.code.microsoft.com/utils/Assembly2.dll および http://www.code.microsoft.com/utils/Assembly2/Assembly2.dll内のアセンブリをプローブします。 どちらの場所にも Assembly2 が見つからない場合、ランタイムは Windows インストーラーに対してクエリを実行します。

こちらも参照ください