4

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

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

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

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

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 绑定。位置指向文件被引用的位置
    • 我相信 VS 在解决方案中加载引用时使用 LoadFrom
  • 强名称绑定失败
    • 未知是什么触发了此加载尝试
    • 只探测了应用程序库

AFAICT,Visual Studio 将程序集加载到解决方案的 AppDomain 中(我希望 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 中找到的程序集。该测试表明它不会是版本控制的问题。

4

1 回答 1

0

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

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

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

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

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

这是故意的吗?


编辑:

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

于 2011-05-17T18:41:29.970 回答