ReflectionOnlyLoadFrom

ReflectionOnlyLoadFrom

本文介绍了奇怪FileLoadException当加载使用Assembly.ReflectionOnlyLoadFrom WPF项目装配引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的MSBuild任务偷窥一个组件内,以获得一些属性的元数据。

I have a custom MSBuild task that peeks inside an assembly to get some attribute meta-data.

Assembly assembly = Assembly.ReflectionOnlyLoadFrom(AssemblyFile)

这是使用我们的自动化构建/发布过程,并一直致力于对完美的使用和类库,控制台应用程序和Web项目引用的程序集。该MSBuild任务被称为又一个的MSBuild进程编制项目。

This is used by our automated build/release process, and has been working perfectly against assemblies used by and referenced from class libraries, console apps and web projects. The MSBuild task is called after another MSBuild process has compiled the projects.

它停下时,我加入其中引用的这个特别的组件的WPF项目工作昨天 - 一个.NET 3.5类库

It stopped working yesterday when I added a WPF project which referenced this particular assembly - a .NET 3.5 class library.

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项目引用。

I know it's WPF related because no exception is thrown if I change the AssemblyFile to point to another assembly in the same solution which isn't referenced by the WPF project.

异常消息提到,

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

它不能从相同的AppDomain中的新位置加载。

请注意大约在同一应用程序域的部分。

Note the part about the same appdomain.

所以,我修改了code捕获这个特定的异常,并期待在CurrentDomain:

So I modified the code to catch this particular exception and look in 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。

It goes without saying that the assembly in question wasn't in the current domain (which may make sense, since another MSBuild process is spawned which does the compilation), so assuming the error message is true, how do I go about figuring out where it lives? It's confusing because the error message to me suggests that it should be CurrentDomain.

或者有人可以有更多WPF的经验解释了为什么这个组件成功构建后仍漂浮在一个应用程序域?

Or can someone with more WPF experience explain why this assembly is still floating around in an app domain after a successful build?

下面的another问题从别人谁也打这个例外。

Here's another question from someone else who has hit this exception.

推荐答案

我的解决办法是去开源:)使用塞西尔,以获取属性 AssemblyFile

My solution was to go open source :) Using Cecil to get Attribute from AssemblyFile:

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;
    }
}

更新蓝鸟评论:

Update for Jays comment:

通常情况下使用: AssemblyFileVersion 的属性属性值,并有二传手逻辑填补了缺失的部分:)

Typically I use: AssemblyFileVersion as the Attribute property value, and have the setter logic fill in the missing pieces :)

下面是如何的属性定义:

Here's how the property is defined:

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;
    }
}

单元测试显示属性的属性值SANS需要preFIX或后缀:

Unit test showing Attribute property value sans required prefix or suffix:

[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");
}

这篇关于奇怪FileLoadException当加载使用Assembly.ReflectionOnlyLoadFrom WPF项目装配引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 22:26