在运行时尝试通过程序集限定名称获取类型时出现奇怪的行为



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

给定的程序集名称或代码库无效。 (HRESULT的例外:0x80131047)

此错误与序列化程序无关;尝试在运行时按类型的程序集限定名加载类型会导致相同的失败。

我已将侦听器附加到AssemblySolve事件以查看发生了什么:

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

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

另一点信息:Assembly.Load(e.Name)始终返回有效的程序集。 我不确定为什么它会起作用,而反序列化期间在幕后使用的方法失败了。

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

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


有关融合测井的更多详细信息...

我已经捕获了导致引发异常的方法调用之前和期间的所有程序集加载。 以下是按创建顺序排列的相关日志:

  • 部分绑定失败
    • 尝试仅按名称加载程序集
    • 仅探测了应用程序基础
  • 通过加载自成功进行部分绑定
    • 哪里引用绑定。位置指向引用文件的位置
    • 我相信VS在解决方案中加载引用时使用LoadFrom。
  • 强名称绑定失败
    • 未知是什么触发了此加载尝试
    • 仅探测了应用程序基础

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

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

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

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


更多有趣的东西...

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

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 中。 此测试表明它不可能是版本控制的问题。

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

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

e用作程序集的名称,因为它与Assembly.Name匹配,因此其中不会有类/类型的名称,那么这里:

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

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

这是故意的吗?


编辑:

抱歉,我发布了此回复,就像您编辑帖子并自己发现错误一样......

相关内容

  • 没有找到相关文章

最新更新