Я пишу приложение, которое можно расширить с помощью плагинов (которые продаются за дополнительную плату). Некоторые из этих плагинов нуждаются в специфичной для плагина конфигурации, которая может быть обновлена пользователем, поэтому конфигурация не является фиксированной.
Теперь я добавил файл конфигурации в такой плагин, но когда плагин загружает 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 пытался загрузить сборку плагина из той же папки, где находится само приложение. Однако плагины хранятся в подпапке приложения.
Решение моей конкретной ситуации (именно поэтому я не создал ответ, поскольку исходная проблема на самом деле не является проблемой) заключается в добавлении зондирующего элемента в конфигурацию приложения, чтобы указать напапка, в которой находятся плагины.Таким образом, подсистема конфигурации также может найти сборку плагина, и все в порядке.
Привет, Марсель