gpt4 book ai didi

c# - 使用 Assembly.ReflectionOnlyLoadFrom 加载 WPF 项目引用的程序集时出现奇怪的 FileLoadException

转载 作者:行者123 更新时间:2023-11-30 18:10:18 29 4
gpt4 key购买 nike

我有一个自定义 MSBuild 任务,可以查看程序集内部以获取一些属性元数据。

Assembly assembly = Assembly.ReflectionOnlyLoadFrom(AssemblyFile)

这被我们的自动构建/发布过程使用,并且一直完美地针对类库、控制台应用程序和 Web 项目使用和引用的程序集。在另一个 MSBuild 进程编译项目后调用 MSBuild 任务。

昨天,当我添加一个引用这个特定程序集的 WPF 项目时,它停止工作了——一个 .NET 3.5 类库。

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 项目引用的另一个程序集,则不会引发异常。

异常消息提到

...已经从不同的位置加载。

无法从同一应用域内的新位置加载它。

注意关于同一个应用域的部分。

所以我修改了代码以捕获这个特定的异常并查看 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 进程来进行编译),所以假设错误消息是正确的,我该怎么做弄清楚它住在哪里?这令人困惑,因为给我的错误消息表明它应该是 CurrentDomain。

或者有更多 WPF 经验的人可以解释为什么这个程序集在成功构建后仍然在应用程序域中 float 吗?

这是 another question来自遇到此异常的其他人。

最佳答案

我的解决方案是开源 :) 使用 CecilAssemblyFile 获取 Attribute:

bool found = false;
string value = string.Empty;
Type attributeType = Type.GetType(Attribute);
AssemblyDefinition assembly = AssemblyFactory.GetAssembly(AssemblyFile);
foreach (CustomAttribute attribute in assembly.CustomAttributes)
{
if (attribute.Constructor.DeclaringType.Name == attributeType.Name)
{
value = attribute.ConstructorParameters[0].ToString();
found = true;
}
}

Jays 评论更新:

通常我使用:AssemblyFileVersion 作为 Attribute 属性值,并让 setter 逻辑填充缺失的部分 :)

属性的定义如下:

string attribute;
[Required]
public string Attribute
{
get { return attribute; }
set
{
string tempValue = value;
if (!tempValue.StartsWith("System.Reflection."))
{
tempValue = "System.Reflection." + tempValue;
}
if (!value.EndsWith("Attribute"))
{
tempValue += "Attribute";
}
attribute = tempValue;
}
}

单元测试显示属性属性值没有必需的前缀或后缀:

[Test]
public void Execute_WithoutSystemReflectionPrefixOrAttributeSuffix_ReturnsExpectedResult()
{
string version = getAssemblyFileVersion();
Assert.IsNotNull(version, "Expected AssemblyFileVersionAttribute to contain value");

task.AssemblyFile = assemblyFile;
task.Attribute = "AssemblyFileVersion";
task.Value = "Bogus";

result = task.Execute();

Assert.IsTrue(result, "Expected execute to pass on valid assembly and attribute name");

Assert.AreEqual(task.Value, version,
"Expected task value to match assembly file version attribute value");
}

关于c# - 使用 Assembly.ReflectionOnlyLoadFrom 加载 WPF 项目引用的程序集时出现奇怪的 FileLoadException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1535549/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com