アセンブリ内を覗いていくつかの属性メタデータを取得するカスタム MSBuild タスクがあります。
Assembly assembly = Assembly.ReflectionOnlyLoadFrom(AssemblyFile)
これは、自動化されたビルド/リリース プロセスで使用され、クラス ライブラリ、コンソール アプリ、および Web プロジェクトによって使用および参照されるアセンブリに対して完全に機能しています。MSBuild タスクは、別の MSBuild プロセスがプロジェクトをコンパイルした後に呼び出されます。
昨日、この特定のアセンブリ (.NET 3.5 クラス ライブラリ) を参照する WPF プロジェクトを追加したところ、機能しなくなりました。
System.IO.FileLoadException: API restriction: The assembly 'file:///bogus.dll' has already loaded from a different location.
It cannot be loaded from a new location within the same appdomain.
at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, StackCrawlMark& stackMark)
at System.Reflection.Assembly.ReflectionOnlyLoadFrom(String assemblyFile)
at RadicaLogic.MSBuild.Tasks.GetAssemblyAttribute.Execute()
at Microsoft.Build.BuildEngine.TaskEngine.ExecuteInstantiatedTask(EngineProxy engineProxy, ItemBucket bucket, TaskExecutionMode howToExecuteTask, ITask task, Boolean& taskResult)
WPF プロジェクトによって参照されていない同じソリューション内の別のアセンブリを指すように AssemblyFile を変更しても例外がスローされないため、WPF 関連であることはわかっています。
例外メッセージには、
... already loaded from a different location.
It cannot be loaded from a new location within the same appdomain.
同じ appdomain に関する部分に注意してください。
そこで、この特定の例外をキャッチして CurrentDomain を調べるようにコードを変更しました。
Assembly assembly = null;
try
{
assembly = Assembly.ReflectionOnlyLoadFrom(AssemblyFile);
}
catch (FileLoadException)
{
List<string> searched = new List<string>();
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
if (Path.GetFileName(asm.CodeBase).Equals(Path.GetFileName(AssemblyFile),
StringComparison.OrdinalIgnoreCase))
{
message = string.Format("Found assembly {0} in current domain",
asm.CodeBase);
MSBuildHelper.Log(this, message, MessageImportance.High);
assembly = asm;
break;
}
else
{
searched.Add(Path.GetFileName(asm.CodeBase));
}
}
if (assembly == null)
{
message = string.Format(
"Unable to find {0} after looking in current domain assemblies {1}",
Path.GetFileName(AssemblyFile), string.Join(", ", searched.ToArray()));
MSBuildHelper.Log(this, message, MessageImportance.High);
}
}
問題のアセンブリが現在のドメインになかったことは言うまでもありません (コンパイルを実行する別の MSBuild プロセスが生成されるため、これは理にかなっている可能性があります)。したがって、エラー メッセージが true であると仮定すると、どこを調べればよいでしょうか。それは住んでいますか?私へのエラーメッセージはそれがCurrentDomainであるべきだと示唆しているので、混乱しています。
または、WPF の経験が豊富な人が、ビルドが成功した後も、このアセンブリがアプリ ドメインにまだ残っている理由を説明できますか?
これは、この例外に遭遇した他の誰かからの別の質問です。