Visual Studio ソリューションには 4 つのプロジェクトがあります (すべて .NET 3.5 をターゲットにしています)。私の問題では、次の 2 つだけが重要です。
- MyBaseProject <- このクラス ライブラリはサードパーティの DLL ファイル (elmah.dll) を参照します
- MyWebProject1 <- この Web アプリケーション プロジェクトには MyBaseProject への参照があります
Visual Studio 2008 で、「参照の追加...」→「参照」タブをクリックし、「elmah.dll」を選択して、MyBaseProjectに elmah.dll 参照を追加しました。
Elmah リファレンスのプロパティは次のとおりです。
- エイリアス - グローバル
- ローカルにコピー - true
- 文化 -
- 説明 - ASP.NET のエラー ログ モジュールとハンドラー (ELMAH)
- ファイルタイプ - アセンブリ
- パス - D:\webs\otherfolder\_myPath\__tools\elmah\Elmah.dll
- 解決済み - 真
- ランタイムバージョン - v2.0.50727
- 指定されたバージョン - false
- 厳密な名前 - false
- バージョン - 1.0.11211.0
MyWebProject1で、「参照の追加...」→「プロジェクト」タブ→「MyBaseProject」を選択して、プロジェクト MyBaseProject への参照を追加しました。この参照のプロパティは、次のメンバーを除いて同じです。
- 説明 -
- パス - D:\webs\CMS\MyBaseProject\bin\Debug\MyBaseProject.dll
- バージョン - 1.0.0.0
Visual Studioでビルドを実行すると、elmah.dll ファイルがMyBaseProject.dll とともにMyWebProject1 の binディレクトリにコピーされます。
ただし、ソリューションのMSBuild をクリーンアップして実行すると(D:\webs\CMS> C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /t:ReBuild /p:Configuration=Debug MyProject.sln 経由) 、ビルド自体には警告やエラーは含まれていないにもかかわらず、MyWebProject1 の bin ディレクトリにelmah.dll がありません。
MyBaseProject の .csproj に、値が "true" のプライベート要素が含まれていることは既に確認しています (これはVisual Studio の" copy local "のエイリアスになります)。
<Reference Include="Elmah, Version=1.0.11211.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\mypath\__tools\elmah\Elmah.dll</HintPath>
**<Private>true</Private>**
</Reference>
(Visual Studio では「ローカルにコピー」が true と表示されていましたが、デフォルトではプライベート タグは .csproj の xml に表示されませんでした。「ローカルにコピー」を false に切り替えて保存し、再度 true に設定して保存しました。)
MSBuild の何が問題なのでしょうか? (elmah.dll) 参照を MyWebProject1 の bin にコピーするにはどうすればよいですか?
すべてのプロジェクトの postbuild コマンドに postbuild コピー アクションを追加したくありません。(MyBaseProject に依存するプロジェクトが多数あると想像してください。)
ベストアンサー1
Visual Studio と MsBuild の間でビルドするときになぜ異なるのかはわかりませんが、MsBuild と Visual Studio でこの問題に遭遇したときに私が見つけたことは次のとおりです。
説明
サンプル シナリオとして、プロジェクト X、アセンブリ A、アセンブリ B があるとします。アセンブリ A はアセンブリ B を参照するため、プロジェクト X には A と B の両方への参照が含まれます。また、プロジェクト X にはアセンブリ A を参照するコード (例: A.SomeFunction()) が含まれます。ここで、プロジェクト X を参照する新しいプロジェクト Y を作成します。
依存関係のチェーンは次のようになります: Y => X => A => B
Visual Studio / MSBuild は、プロジェクト X で必要であると検出された参照のみをプロジェクト Y に持ち込むようスマートに動作します。これは、プロジェクト Y での参照汚染を回避するためです。問題は、プロジェクト X にはアセンブリ B を明示的に使用するコード (例: B.SomeFunction()) が実際には含まれていないため、VS/MSBuild は B が X で必要であることを検出せず、プロジェクト Y の bin ディレクトリにコピーしないことです。コピーされるのは、X アセンブリと A アセンブリのみです。
解決
この問題を解決するには 2 つのオプションがあり、どちらの場合もアセンブリ B がプロジェクト Y の bin ディレクトリにコピーされます。
- プロジェクト Y のアセンブリ B への参照を追加します。
- アセンブリ B を使用するプロジェクト X のファイルにダミー コードを追加します。
個人的には、いくつかの理由からオプション 2 を好みます。
- 将来、プロジェクト X を参照する別のプロジェクトを追加する場合、アセンブリ B への参照も含める必要があることを覚えておく必要はありません (オプション 1 の場合のように)。
- ダミー コードがなぜ必要で、削除してはいけないのかを明示的なコメントで説明できます。そのため、誰かが誤ってコードを削除した場合でも (未使用のコードを探すリファクタリング ツールなどを使用して)、ソース管理からそのコードが必要であることが簡単にわかり、復元できます。オプション 1 を使用し、誰かがリファクタリング ツールを使用して未使用の参照をクリーンアップした場合、コメントは表示されず、.csproj ファイルから参照が削除されたことだけが表示されます。
以下は、このような状況に遭遇したときに私が通常追加する「ダミー コード」のサンプルです。
// DO NOT DELETE THIS CODE UNLESS WE NO LONGER REQUIRE ASSEMBLY A!!!
private void DummyFunctionToMakeSureReferencesGetCopiedProperly_DO_NOT_DELETE_THIS_CODE()
{
// Assembly A is used by this file, and that assembly depends on assembly B,
// but this project does not have any code that explicitly references assembly B. Therefore, when another project references
// this project, this project's assembly and the assembly A get copied to the project's bin directory, but not
// assembly B. So in order to get the required assembly B copied over, we add some dummy code here (that never
// gets called) that references assembly B; this will flag VS/MSBuild to copy the required assembly B over as well.
var dummyType = typeof(B.SomeClass);
Console.WriteLine(dummyType.FullName);
}