尝试在运行时通过AssemblyQualifiedName获取Type时出现奇怪的行为

时间:2011-05-17 18:24:40

标签: .net assembly-resolution fileloadexception

尝试使用NetDataContractSerializer反序列化类型时,我收到了FileLoadException:

  

给定的程序集名称或代码库无效。 (来自HRESULT的异常:0x80131047)

此错误与序列化程序无关;尝试在运行时通过Assembly Qualified Name加载类型会导致同样的失败。

我已经在AssemblyResolve event附加了一位听众,看看发生了什么:

ResolveEventHandler reh = (o, e) =>
{
    var tryGet = AppDomain.CurrentDomain.GetAssemblies()
                          .Where(x => x.FullName == e.Name).FirstOrDefault();
    if (tryGet != null)
        return tryGet;
    //EDIT:  Crap, the following line is a stupid bug STUPID!  Ignore!
    return Type.GetType(e.Name).Assembly;
};

using (var stream = System.IO.File.OpenRead(serializedObjectFilename))
{
    try
    {
        AppDomain.CurrentDomain.AssemblyResolve += reh;
        var ser = new NetDataContractSerializer();
        return ser.Deserialize(stream) as MyType;
    }
    finally
    {
        AppDomain.CurrentDomain.AssemblyResolve -= reh;
    }
}

通过处理程序调试可以看出名义上的“奇怪行为”。虽然tryGet永远不是null(在这种情况下,所需的程序集始终加载到AppDomain中),但操作总是会失败(如果留给自己)。 换句话说,调用Type.GetType(e.Name).Assembly会导致抛出FileLoadException。 编辑:我将程序集的强名称与程序集限定名称混为一谈类型;请忽略那个错误。具有讽刺意味的是,它没有引发不同的错误,所以在提出这个问题之前我没有抓住这个。

另一部分信息:Assembly.Load(e.Name)始终返回有效的程序集。我不确定为什么这样可行,而反序列化过程中幕后使用的方法失败。

Fusion Log报告加载程序正在尝试加载正确的程序集,但由于在可执行文件的专用路径中找不到程序集,因此失败。

为什么在AppDomain中已加载程序集时尝试加载程序集?


有关融合记录的更多细节......

我在方法调用之前和期间捕获了导致异常抛出的所有程序集加载。以下是相关日志,按创建顺序:

  • 部分绑定失败
    • 仅按名称
    • 尝试加载程序集
    • 仅探测应用基础
  • 通过LoadFrom SUCCEEDED进行部分绑定
    • Where-ref bind。位置指向文件的引用位置
    • 我认为VS在解决方案中加载引用时使用LoadFrom
  • 强名称绑定FAILED
    • 未知触发此次加载尝试的原因
    • 仅探测应用基础

AFAICT,Visual Studio将程序集加载到解决方案的AppDomain中(ffs我希望Fusion Log捕获尝试加载的AppDomain;它毕竟记录了调用程序集)。

在此之后,我进行了反序列化调用。结果是Fusion中的单个日志:

  

绑定结果:hr = 0x80070002。系统找不到指定的文件。

同样,Fusion正试图通过其强名称从可执行文件的应用程序库加载。一件好事;它试图从GAC加载,因此一旦部署,我可能没有相同的问题。但是我仍然不知道为什么程序集不能位于appdomain中。


更有趣的东西......

这会引发对反序列化的调用:

MyType test = new MyType ();
var serialized = Serializer.ToXml(test);
// the following line fails with a FileLoadException
var deserialized = Serializer.FromXml<MyType>(serialized);

其中ToXml和FromXml都使用NetDataContractSerializer和Write / ReadObject。程序集的早期执行是从程序包的安装目录加载的,但由于某种原因,NDCS不希望使用AppDomain中的程序集。此测试表明它不是版本控制的问题。

1 个答案:

答案 0 :(得分:0)

我在代码中发现奇怪的一件事就是:

GetAssemblies().Where(x => x.FullName == e.Name)

e用作程序集的名称,因为它匹配Assembly.Name,因此不会有类/类型的名称,然后在这里:

return Type.GetType(e.Name).Assembly;

e用作完全程序集限定的类型名称,我认为它将包含类/类型名称和程序集名称。

这是故意的吗?


修改

抱歉,我在您编辑帖子时发布了此回复,并自行抓错了...