Я создал настраиваемый раздел конфигурации для DLL плагина, который хранит XML файл .config в отдельном файле (из основного исполняемого приложения).
Здесь образец пользовательского класса раздела:
using System;
using System.Configuration;
namespace PluginFramework.MyConfiguration
{
public class MyConfigurationSettings : ConfigurationSection
{
private Configuration _Config = null;
#region ConfigurationProperties
/// <summary>
/// A custom XML section for an application configuration file.
/// </summary>
[ConfigurationProperty("MyProjects", IsDefaultCollection = true)]
public MyProjectConfigurationCollection MyProjects
{
get { return (MyProjectConfigurationCollection) base["MyProjects"]; }
}
// ...
#endregion
/// <summary>
/// Private Constructor used by our factory method.
/// </summary>
private MyConfigurationSettings () : base () {
// Allow this section to be stored in user.app. By default this is forbidden.
this.SectionInformation.AllowExeDefinition =
ConfigurationAllowExeDefinition.MachineToLocalUser;
}
// ...
#region Static Members
/// <summary>
/// Gets the current applications <MyConfigurationSettings> section.
/// </summary>
/// <param name="ConfigLevel">
/// The <ConfigurationUserLevel> that the config file
/// is retrieved from.
/// </param>
/// <returns>
/// The configuration file <MyConfigurationSettings> section.
/// </returns>
public static MyConfigurationSettings GetSection (ConfigurationUserLevel ConfigLevel)
{
string appDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string localDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
System.Configuration.ExeConfigurationFileMap exeMap = new ExeConfigurationFileMap();
exeMap.ExeConfigFilename = System.IO.Path.Combine(appDataPath, @"MyCompany\MyPluginApp\Default.config");
exeMap.RoamingUserConfigFilename = System.IO.Path.Combine(appDataPath, @"MyCompany\MyPluginApp\Roaming.config");
exeMap.LocalUserConfigFilename = System.IO.Path.Combine(localDataPath, @"MyCompany\MyPluginApp\Local.config");
System.Configuration.Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(exeMap,ConfigLevel);
MyConfigurationSettings myConfigurationSettings = null;
try {
myConfigurationSettings = (MyConfigurationSettings)Config.GetSection("MyConfigurationSettings");
}
catch (System.Exception ex) {
// ConfigurationErrorsException caught here ...
}
if (myConfigurationSettings == null) {
myConfigurationSettings = new MyConfigurationSettings();
Config.Sections.Add("MyConfigurationSettings", myConfigurationSettings); }
}
if(myConfigurationSettings != null) {
myConfigurationSettings._Config = Config;
}
return myConfigurationSettings;
}
#endregion
}
} // PluginFramework.MyConfiguration
XML.config, сгенерированный при сохранении в первый раз, выглядит следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- The exception complains about the following line (assembly attributes are compliant): -->
<section name="MyConfigurationSettings" type="PluginFramework.MyConfiguration.MyConfigurationSettings, PluginFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToLocalUser" />
</configSections>
<MyConfigurationSettings>
<!-- Config properties are serialized fine according MyConfigurationSettings
properties marked with the ConfigurationProperty attribute ... -->
<MyProjects>
<MyProjectConfiguration GUID="{4307AC92-8180-4686-9322-830312ED59AB}">
<!-- ... more complex configuration elements -->
</MyProjectConfiguration>
</MyProjects>
</MyConfigurationSettings>
</configuration>
Когда этот XML пытается загрузить с помощью Config.GetSection()
при последующих запусках, я поймаю ConfigurationErrorsException
в строке, помеченной в примере XML, заявив, что сборка MyPlugin
или одна из ее зависимостей не может быть (пожалуйста, простите, что я не отправляю оригинальное сообщение об исключении, но у меня есть только на немецком языке, и сомневаюсь, что этот текст будет полезен здесь). Внутреннее исключение исходит от System.IO
при попытке загрузить сборку и получить отражение для разрешения типа класса MyConfigurationSettings.
Чтобы уточнить ситуацию, код сверху размещен внутри фреймворка DLL (сборка), на который ссылается фактическая DLL-плагин, загружаемая из основного приложения.
Следующая диаграмма UML иллюстрирует отношения нескольких компонентов:
Оглядываясь немного вокруг этой проблемы, у меня возникает ощущение, что нужно сильное имя (знак) сборки, экспортирующей класс MyConfigurationSettings
(т.е. PluginFramework
) и зарегистрировать его с помощью GAC. Я еще не пробовал этого и хотел бы избежать этого шага по нескольким причинам (прежде чем знать, может ли это даже помочь, и это единственный выбор для решения проблемы).
Итак, вот вопросы (извините, что я размещаю на самом деле 4 вопроса здесь, но они так сильно связаны, что не имеет смысла создавать для них отдельные SO-вопросы).
-
Могу ли я решить проблему сбоя локации, решив называть эту сборку и регистрировать ее с помощью GAC?
-
Похоже, что сборка, на которую жалуется управление конфигурацией, гарантированно загружается (поскольку она сама вызывает
Configuration.GetSection()
).
Может ли быть способ зарегистрировать сборку или соответствующие типы/сериализаторы типа конфигурации явно с классомConfigurationManager
илиConfguration
? -
Мне также интересна дополнительная информация о комментарий Hans Passant, в котором упоминается, что это может быть проблемой, вызванной тем, как загружается (первичная) сборка из основное приложение. У меня нет контроля над этим механизмом, и если это вызывает поведенческое поведение, я бы хотел знать, есть ли разумное решение?
-
Другая идея (если что-либо из вышеперечисленного не может показать способ) заключается в том, чтобы полностью управлять XML-форматом конфигурации (используя поддержку де-/сериализации XML) и откуда загрузить и слить файлы конфигурации. Если это наиболее подходящий вариант, может ли кто-нибудь дать хорошие указатели, как это сделать эффективно (наименее необходимый код для управления путями и слияния)?
Update:
Поскольку никто, кажется, не в состоянии дать больше информации об этом вопросе (ответах), на самом деле я не догоняю меня дальше), я перехожу к варианту с 4., делая все это вручную.