今回はVisual Studioで開発をしている過程で遭遇した事象についてのお話です。
Problem
OracleDBのアンマネージ・コードのドライバ Oracle.DataAccess.dll
に依存するアプリケーションを構築・運用。
あるときまでは、Visual Studio(msbuild)のビルド成果物に当該アセンブリが含まれていたのだが、何かをきっかけにして含まれないようになってしまった。
このかん .csproj
ファイルの参照設定に変化はない。
当該アセンブリを参照する <Reference/>
の子要素は <SpecificVersion/>
と <HintPath/>
のみで、 <Provate/>
は存在しなかった:
<Reference Include="Oracle.DataAccess, Version=4.122.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Lib\Oracle.DataAccess.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
Visual Studioから見ると<Private/>
に対応する設定項目である「ローカルにコピー」は True
となっている:
Solution
「ローカルにコピー」(CopyLocal)を一旦 False
にしたあと True
にする。
あるいは、*.csproj
ファイルをテキストエディアなどで開き、<Reference/>
の子要素に <Provate/>
を追加する:
<Reference Include="Oracle.DataAccess, Version=4.122.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Lib\Oracle.DataAccess.dll</HintPath>
<Private>True</Private>
</Reference>
この状態でビルドするとビルド成果物に当該アセンブリが含まれるようになる。
なぜこのような挙動になるのか、あれこれ調べてみたがわかっていない。
Microsoft社のリファレンスによれば、「ローカルにコピー」(CopyLocal)ないし <Private/>
のデフォルトの振る舞いは状況により異なる:
The project-assigned value of CopyLocal is determined in the following order:
- If the reference is another project, called a project-to-project reference, then the value is true.
- If the assembly is found in the global assembly cache, the value is false.
- As a special case, the value for the mscorlib.dll reference is false.
- If the assembly is found in the Framework SDK folder, then the value is false.
- Otherwise, the value is true.
つまり
「ローカルにコピー」の値は次の順序で決定される:
- 別プロジェクトへの参照の場合、値は
True
- 当該アセンブリがグローバル・キャッシュ・アセンブリに存在する場合、値は
False
- 特殊ケースとして、アセンブリがmscorlib.dllへの参照である場合、値は
False
- 当該アセンブリがフレームワークSDK内に存在する場合、値は
False
- それ以外の場合、値は
true
コピーするかしないかはかなりの程度状況依存ということである。
ただ、今回ここで示されている条件はどれも変化していない。。
おまけに、今試みに手元にあった Visutal Studio 2022で実験をしてみると、当該アセンブリがグローバル・キャッシュ・アセンブリに存在し かつ <Private/>
要素なしの場合でもアセンブリはコピーされている。。。
結局「なぜ」はよくわからないのだが、「ローカルにコピー」のデフォルトの振る舞いは状況により異なる。
アセンブリがコピーされない問題に遭遇したら上述の通り、明示的にコピーを指示するべし。