Как исправить «Не удалось загрузить файл или сборку» при загрузке файла конфигурации для DLL - PullRequest
0 голосов
/ 19 апреля 2019

Я пишу приложение, которое можно расширить с помощью плагинов (которые продаются за дополнительную плату). Некоторые из этих плагинов нуждаются в специфичной для плагина конфигурации, которая может быть обновлена ​​пользователем, поэтому конфигурация не является фиксированной.

Теперь я добавил файл конфигурации в такой плагин, но когда плагин загружает ConfigurationSection (сопоставленный с классом), он выдает исключение, что он не может загрузить файл или сборку, в которой определен ConfigurationSection, что является точно такой же сборкой, в которой определен код плагина (т.е. плагин уже загружен).

В моем основном приложении я использую следующий код, чтобы найти класс плагина в сборке плагина и создать его экземпляр (который загружает сборку в домен приложений (я упустил все проверки ошибок для удобства чтения):

// Load the assembly
AssemblyName assemblyName = new AssemblyName();
assemblyName.CodeBase = assemblyPath;
Assembly assembly = Assembly.Load(assemblyName);

// Load the types from the assembly
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
    if (null != type.GetInterface(typeof(IPlugin).FullName))
    {
        IPlugin plugin = Activator.CreateInstance(type) as IPlugin;
        // ... do something with the plugin
    }
}

Теперь у меня есть сборка MyPlugin.dll, в которой реализован плагин. В этом проекте у меня есть файл MyPlugin.dll.config, который я копирую в выходную папку при сборке плагина. MyPlugin.dll.config имеет следующее содержимое:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section allowExeDefinition="MachineToLocalUser" name="mysettings" restartOnExternalChanges="false" requirePermission="false" type="Plugin.MySettings, MyPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1234567890abcdef" />
    </configSections>
</configuration>

Также в плагине я определил класс Plugin.MySettings:

namespace Plugin
{
    public class MySettings : ConfigurationSection
    {
        public MySettings() : base() {}

        [ConfigurationProperty("someproperty", DefaultValue = null, IsRequired = false]
        public string SomeProperty
        {
            get { return (string)this["someproperty"]; }
            set { this["someproperty"] = value; }
        }
    }
}

Затем я пытаюсь загрузить файл конфигурации dll следующим образом (для этого примера я просто использую подпапку папок данных специального приложения, но в реальном приложении я использую более глубокую иерархию для этих файлов конфигурации, но это не должно иметь значения ):

ExeConfigurationFileMap configurationMap = new ExeConfigurationFileMap();
configurationMap.ExeConfigFilename = assembly.Location + ".config";
configurationMap.LocalUserConfigFilename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                                                        "Plugins",
                                                        "MyPlugin.config");
configurationMap.RoamingUserConfigFilename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                                                          "Plugins",
                                                          "MyPlugin.config");
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configurationMap, ConfigurationUserLevel.PerUserRoamingAndLocal);
MySettings settings = config.GetSection("mysettings") as MySettings;

Однако, когда я делаю это, открытие файла конфигурации (вызов GetSection) вызывает исключение:

An error occurred creating the configuration section handler for mysettings: Could not load file or assembly 'MyPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1234567890abcdef' or one of its dependencies. The system cannot find the file specified. (<outputpath>\MyPlugin.dll.config line 4)

Сейчас я уже попробовал следующие вещи:

1. Добавьте пустой тег mysettings в файл конфигурации:

Я добавил пустой тег mysettings в файл конфигурации, чтобы он выглядел следующим образом:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section allowExeDefinition="MachineToLocalUser" name="mysettings" restartOnExternalChanges="false" requirePermission="false" type="Plugin.MySettings, MyPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1234567890abcdef" />
    </configSections>
    <mysettings />
</configuration>

Это дало точно такое же исключение, которое было выброшено изначально.

2. Удалите тег configSections

Я удалил тег configSections в файле конфигурации, чтобы он выглядел следующим образом:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <section allowExeDefinition="MachineToLocalUser" name="mysettings" restartOnExternalChanges="false" requirePermission="false" type="Plugin.MySettings, MyPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1234567890abcdef" />
</configuration>

Это не приводило к исключению, а вместо этого приводило к тому, что переменная настроек была равна нулю. При ближайшем рассмотрении выяснилось, что в этом случае тип mySettings ConfigurationSection в этом случае - System.Configuration.DefaultSection.

Я должен что-то пропустить, но сборка MyPlugin загружена (потому что код для загрузки файла конфигурации выполняется из сборки плагина. Обратите внимание, что код выполняется, пока в папках пользовательских данных нет файлов конфигурации). , только данный файл конфигурации рядом с файлом DLL в выходной папке.

Я уже просматривал другие статьи в Интернете и о переполнении стека, но в них не используются пользовательские ConfigurationSections, а непосредственно пары ключ-значение в appSettings в файле конфигурации, и также кажется, что эти конфигурации являются фиксированными (т.е. не обновляется пользователями). Примеры этих несопоставимых вопросов: Файл конфигурации DLL C # и Эквивалент «app.config» для библиотеки (DLL) . Однако я хотел бы использовать класс в качестве ConfigSection, чтобы свойства легче было извлечь в местах в коде плагина, где они необходимы.

Могу ли я что-нибудь сделать, чтобы это заработало?

UPDATE

Я углубился в проблему. Проблема заключалась в том, что ConfigurationManager пытался загрузить сборку плагина из той же папки, где находится само приложение. Однако плагины хранятся в подпапке приложения.

Решение моей конкретной ситуации (именно поэтому я не создал ответ, поскольку исходная проблема на самом деле не является проблемой) заключается в добавлении зондирующего элемента в конфигурацию приложения, чтобы указать напапка, в которой находятся плагины.Таким образом, подсистема конфигурации также может найти сборку плагина, и все в порядке.

Привет, Марсель

...