为什么XmlSerializer.Deserialize会抛出System.IO.FileLoadException异常?

6
我遇到了一个让我感到困惑的XML反序列化问题。
我正在构建一个支持本地定制各种服务的应用程序。我实现了一个抽象的ServiceLocator类,它的方法返回各种对象。每个自定义安装都负责实现这个类的子类,并提供这些方法的实现。该类的核心代码如下:
public abstract class ServiceLocator
{
    public static void Initialize(string customFeaturesPath)
    {
        Assembly a = Assembly.LoadFrom(customFeaturesPath);
        Type t = a.GetExportedTypes()
            .AsEnumerable()
            .Where(x => x.IsSubclassOf(typeof (ServiceLocator)))
            .First();
        Default = (ServiceLocator)a.CreateInstance(t.FullName);
    }

    public static ServiceLocator Default { get; private set; }

    public abstract DefaultValuesContainer CreateDefaultValuesContainer();
}

这个很好用:我从应用程序配置文件中获取自定义功能程序集的路径,程序调用Initialize,然后应用程序就可以调用ServiceLocator.Default上的各种方法,并返回相应的服务定制实现。
其中之一的服务是DefaultValuesContainer。这是一个简单的对象,公开需要在用户设置文件中持久化值的属性。我的想法是将此对象序列化为类型为string的单个用户设置。它生成了一个您不希望手动编辑的用户设置文件,但我很满意。
下面是ServiceLocator.CreateDefaultValuesContainer的具体实现:
protected override DefaultValuesContainer CreateDefaultValuesContainer(string serializedXml)
{
    DefaultValuesContainer c = new ClientDefaultValuesContainer();

    if (string.IsNullOrEmpty(serializedXml))
    {
        return c;
    }
    XmlSerializer x = new XmlSerializer(c.GetType());
    return (DefaultValuesContainer) x.Deserialize(new StringReader(serializedXml));
}

现在有一个问题。
我已经使用 NUnit 为此构建了单元测试。当我在练习客户端定制功能的测试夹具类中运行测试时,它们可以正常工作。但是,当我运行整个测试套件时,上述方法的最后一行会抛出以下异常:
System.InvalidOperationException : There is an error in XML document (0, 0).
  ----> System.IO.FileLoadException : Could not load file or assembly 'ClientCustomFeatures, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Invalid pointer (Exception from HRESULT: 0x80004003 (E_POINTER))
  ----> System.ArgumentNullException : Value cannot be null.
Parameter name: path1

我对此感到困惑。 SetUp 方法仍在运行,ServiceLocator.Default 仍返回一个类型为 ClientServiceLocator 的对象,这意味着它已加载了 ClientCustomFeatures 程序集。事实上,抛出异常的方法就在我被告知无法加载的程序集中。 XmlSerializer 在这里尝试做什么?为什么要尝试加载已经加载的程序集?“无效指针”是什么意思?最重要的是,我应该如何调试这样的问题?

2
我不知道具体的错误,但请注意XmlSerializer使用代码生成和动态编译,因此它正在尝试创建一个引用所需程序集的程序集。看起来这个新(生成的)程序集对引用不满意。例如,所有必要的类型是否都是“public”? - Marc Gravell
3
肯定是引用问题。在反编译器中打开ClientCustomFeatures.dll文件,并查找可能不存在的任何引用。 - Chris Martin
4个回答

1

如果您的自定义程序集不知道在哪里加载包含ClientCustomFeatures类的程序集,则会发生这种情况。当您将自定义程序集部署到不在主程序集路径中且主程序集不在gac中的位置时,就会发生这种情况。因此,如果您的自定义程序集是从主程序集的子目录加载的,这个问题应该就会消失。但是,如果它们位于任意位置,您将会遇到问题,因为它们需要加载您的主程序集,以便访问ClientCustomFeatures类型。


好的,所有程序集都在同一个目录中,所以我不认为这是问题所在。 - Robert Rossney
1
嗨,罗伯特,请看一下这个网站:http://msdn.microsoft.com/en-us/library/aa302290.aspx。它有许多出色的故障排除想法,涉及到你遇到的问题以及可能发生的原因。还有一个链接到一个工具,应该可以帮助你进行故障排除。由于我们无法访问您所有的代码,因此我们无法为您完成此操作,但我很有兴趣知道这次小冒险的结果是什么 :) 您需要查看“构造函数中的异常”部分。 - Kell
刚想到一件事:NUnit 运行在临时缓存位置,可能没有适当的权限来加载所有程序集和生成类。但是请阅读上面的 URL,它有更多的调查路线供您参考。 - Kell

0
尝试替换这行代码:
XmlSerializer x = new XmlSerializer(c.GetType()); 

使用:

XmlSerializer x = new XmlSerializer(c.GetType(), new Type[] { typeof(DefaultValuesContainer), typeof(ClientDefaultValuesContainer) }); 

0

我在程序集加载器(Fusion?)方面遇到了问题,当一个程序集加载另一个程序集时,后者本身具有(非 GAC)引用。 YourDLL.XmlSerializers.dll 可能是这样的一个程序集。尝试关闭 Visual Studio 的选项以自动生成 XML 序列化程序集(项目选项)- 这将删除额外的程序集(因此也就消除了对它的依赖)。


0

融合日志查看器

为了帮助诊断类似这样的程序集加载问题,请查看融合日志查看器(也称fuslogvw.exe)。

Fusion == .NET组件,用于定位和加载程序集。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接