Я хотел бы иметь xml файл конфигурации следующим образом:
Как точно я располагаю взаимодействие между PluginsConfigurations, UsePluginCollection и классами UsePlugin в моем коде?
Я нашел это учебное руководство онлайн, но оно представит элемент в плагинах, который окружает набор использования, и мне не нужно это.
Это - то, что я имею до сих пор, но его не совсем правильное
Если MyApp.PluginsConfiguration является секцией ConfigurationSection, то вы можете определить новый класс, унаследованный от ConfigurationElementCollection и сделать его ConfigurationProperty из MyApp.PluginsConfiguration
Проверьте в этой статье для получения более подробной информации об этих типах. Также я написал в блоге о том, что имеет вложенные свойства, но не специально для коллекций.
Правка: Здесь есть кое-какой код. Приведем этот бит в web.config:
<configSections>
<section name="plugins"
type="WebApplication1.PluginsConfiguration, WebApplication1"/>
</configSections>
<plugins>
<use assembly="MyApp.Plugin1.dll"/>
<use assembly="MyApp.Plugin2.dll"/>
</plugins>
Вот классы для этого. Обратите внимание, что, возможно, есть NullReferenceExceptions, с которыми нужно будет работать.
namespace WebApplication1
{
public class PluginsConfiguration : ConfigurationSection
{
private static ConfigurationPropertyCollection properties;
private static ConfigurationProperty propPlugins;
static PluginsConfiguration()
{
propPlugins = new ConfigurationProperty(null, typeof(PluginsElementCollection),
null,
ConfigurationPropertyOptions.IsDefaultCollection);
properties = new ConfigurationPropertyCollection { propPlugins };
}
protected override ConfigurationPropertyCollection Properties
{
get
{
return properties;
}
}
public PluginsElementCollection Plugins
{
get
{
return this[propPlugins] as PluginsElementCollection;
}
}
}
public class PluginsElementCollection : ConfigurationElementCollection
{
public PluginsElementCollection()
{
properties = new ConfigurationPropertyCollection();
}
private static ConfigurationPropertyCollection properties;
protected override ConfigurationPropertyCollection Properties
{
get
{
return properties;
}
}
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.BasicMap;
}
}
protected override string ElementName
{
get
{
return "use";
}
}
protected override ConfigurationElement CreateNewElement()
{
return new PluginsElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
var elm = element as PluginsElement;
if (elm == null) throw new ArgumentNullException();
return elm.AssemblyName;
}
}
public class PluginsElement : ConfigurationElement
{
private static ConfigurationPropertyCollection properties;
private static ConfigurationProperty propAssembly;
protected override ConfigurationPropertyCollection Properties
{
get
{
return properties;
}
}
public PluginsElement()
{
propAssembly = new ConfigurationProperty("assembly", typeof(string),
null,
ConfigurationPropertyOptions.IsKey);
properties = new ConfigurationPropertyCollection { propAssembly };
}
public PluginsElement(string assemblyName)
: this()
{
AssemblyName = assemblyName;
}
public string AssemblyName
{
get
{
return this[propAssembly] as string;
}
set
{
this[propAssembly] = value;
}
}
}
}
И чтобы получить к ним доступ, этот фрагмент кода должен помочь:
var cfg = WebConfigurationManager.GetWebApplicationSection("plugins") as PluginsConfiguration;
var sb = new StringBuilder();
foreach(PluginsElement elem in cfg.Plugins)
{
sb.AppendFormat("{0}<br/>", elem.AssemblyName);
}
testLabel.Text = sb.ToString();
В основном, у нас есть ConfigurationSection, который обрабатывает элемент плагинов. В нём мы указываем свойство ConfigurationElementCollection и объявляем его коллекцией по умолчанию (теоретически под одним корневым узлом можно иметь несколько различных коллекций).
PluginsElementCollection реализует коллекцию ConfigurationElementCollection. ElementName должно быть именем тега, в нашем случае "use". Также, GetElementKey должен быть переопределён и должен возвращать атрибут, который является уникальным среди записей.
PluginsElement реализует тэг одиночного использования. Мы определяем только одно свойство: AssemblyName, которое сопоставляется с атрибутом assembly.
Я не утверждаю, что полностью понимаю все это (особенно ConfigurationElementCollection и здесь не рассматриваются различные свойства BaseAdd, BaseGet и т.д.), но могу утверждать, что это работает :)
Кроме того, оно не использует никаких атрибутов. Ненавижу атрибуты - к счастью, все эти атрибуты могут быть преобразованы в правильный код. Можно использовать тот или иной (или оба).
.На основе данного руководства можно легко создать конфигурацию XML следующим образом:
<MyApp>
<Plugins>
<add assembly="MyApp.Plugin1.dll" />
<add assembly="MyApp.Plugin2.dll" />
</Plugins>
</MyApp>
, что я нахожу вполне приемлемым. Есть ли причина, по которой это было бы неприемлемо?
Редактирование:
Я не уверен, как именно это сделать с учебником. Вам понадобится какой-нибудь промежуточный элемент (например, в учебнике есть "действия") - Джордж Мауэр
Хорошо, примерьте это для размера. Возможно, у меня есть несколько опечаток, так как я копирую/вставляю/редактирую какой-нибудь код, который делает то, что Вы хотите, но он должен работать с XML, который я определил выше.
public sealed class MyAppConfiguration : ConfigurationSection
{
public const string MyAppConfigurationTagName = "MyApp";
[ConfigurationProperty(MyAppConfigurationTagName, IsRequired = true)]
public PluginConfigurationCollection Plugins
{
get
{
return this[MyAppConfigurationTagName] as PluginConfigurationCollection;
}
set
{
this[MyAppConfigurationTagName] = value;
}
}
}
public sealed class PluginConfigurationItem : ConfigurationElement
{
// repeat this pattern for each additional attribute you want in the <add /> tag.
// Only the assembly="foo.dll" portion is defined in this class, and is accessed
// via the AssemblyName property.
public const string AssemblyPropertyName = "assembly";
[ConfigurationProperty(AssemblyPropertyName, IsRequired = true, IsKey = true)]
public string AssemblyName
{
get
{
return this[AssemblyPropertyName] as string;
}
set
{
this[AssemblyPropertyName] = value;
}
}
}
public class PluginConfigurationCollection : ConfigurationElementCollection, IEnumerable<PluginConfigurationItem>
{
public const string PluginsElementName = "Plugins";
protected override ConfigurationElement CreateNewElement()
{
return new PluginConfigurationItem();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((PluginConfigurationItem)element).AssemblyName;
}
protected override string ElementName
{
get
{
return PluginsElementName;
}
}
// this is extraneous, but I find it very useful for enumerating over a configuration collection in a type-safe manner.
#region IEnumerable<PluginConfigurationItem> Members
public new IEnumerator<PluginConfigurationItem> GetEnumerator()
{
foreach(PluginConfigurationItem item in (this as IEnumerable))
{
yield return item;
}
}
#endregion
}