Почему XmlSerializer.Deserialize создает исключение System.IO.FileLoadException? - PullRequest
6 голосов
/ 27 сентября 2010

У меня проблема с десериализацией 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 здесь?Почему он пытается загрузить сборку, которая уже загружена?Что на земле означает «Неверный указатель»?И прежде всего, как я должен отлаживать что-то вроде этого?

Ответы [ 4 ]

1 голос
/ 27 октября 2010

Если ваша пользовательская сборка не знает, куда загрузить сборку, содержащую класс ClientCustomFeatures, это произойдет. Это происходит, когда вы развернули свою пользовательскую сборку в месте, которое не находится в пути вашей основной сборки, а ваша основная сборка не находится в gac. Поэтому, если ваши пользовательские сборки загружаются из подкаталогов вашей основной сборки, это должно прекратиться. Однако если они расположены в произвольных местах, у вас возникнет проблема, поскольку им нужно загрузить основную сборку, поскольку им необходим доступ к типу ClientCustomFeatures.

0 голосов
/ 15 октября 2010

Fusion Log Viewer

Чтобы помочь в диагностике подобных проблем с загрузкой сборок, взгляните на Fusion Log Viewer (AKA fuslogvw.exe).

Fusion == .NET-компонент, который находит и загружает сборки.

0 голосов
/ 16 октября 2010

Попробуйте заменить строку:

XmlSerializer x = new XmlSerializer(c.GetType()); 

с:

XmlSerializer x = new XmlSerializer(c.GetType(), new Type[] { typeof(DefaultValuesContainer), typeof(ClientDefaultValuesContainer) }); 
0 голосов
/ 05 октября 2010

У меня были проблемы с загрузчиком сборок (Fusion?), Когда одна сборка загружает другую сборку, которая сама имеет ссылки (не GAC).YourDLL.XmlSerializers.dll может быть одной из таких сборок.Попробуйте отключить параметр Visual Studio для автоматической генерации сборки сериализации XML (параметры проекта) - это удалит дополнительную сборку (и, следовательно, зависимость от нее).

...