我想要一个xml配置文件,如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="plugins" type="MyApp.PluginsConfiguration, MyApp"/>
</configSections>
<plugins>
<use assembly="MyApp.Plugin1.dll" />
<use assembly="MyApp.Plugin2.dll" />
</plugins>
</configuration>
我如何安排代码中PluginsConfigurations,UsePluginCollection和UsePlugin类之间的相互作用?
我在网上发现了this tutorial,但它会在插件中引入一个围绕使用集合的元素,我不需要这个。
This是我迄今为止所做的,但它不太正确
答案 0 :(得分:17)
如果MyApp.PluginsConfiguration是ConfigurationSection,那么您可以定义一个继承自ConfigurationElementCollection的新类,并使新类成为MyApp.PluginsConfiguration的ConfigurationProperty
查看this article以获取有关这些类型的一些深入信息。我也blogged about有嵌套属性,但不是专门用于集合。
编辑:这里有一些代码。给出了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();
基本上我们有一个处理plugins-element的ConfigurationSection。在这里,我们指定一个ConfigurationElementCollection属性并将其声明为默认集合(理论上你可以在一个根节点下有多个不同的集合)。
PluginsElementCollection实现ConfigurationElementCollection。 ElementName必须是标记的名称,在我们的例子中是“use”。此外,需要重写GetElementKey,并且应该返回条目中唯一的属性。
然后PluginsElement实现单个use标记。我们只定义一个属性:AssemblyName,它映射到assembly-attribute。
我没有声称完全理解所有这些(特别是ConfigurationElementCollection,它的各种BaseAdd,BaseGet等属性在这里没有真正探索过),但我可以声称这有效:)
此外,它不使用任何属性。我讨厌属性 - 幸运的是,所有这些属性都可以转换为正确的代码。你可以使用其中一个(或两个)。
答案 1 :(得分:4)
根据本教程,您可以轻松创建XML配置,如下所示:
<MyApp>
<Plugins>
<add assembly="MyApp.Plugin1.dll" />
<add assembly="MyApp.Plugin2.dll" />
</Plugins>
</MyApp>
我认为完全可以接受。这是不可接受的原因吗?
修改强>
我不确定如何使用本教程完成这项工作。你需要某种中间元素(比如教程中有“动作”) - George Mauer
好的,试试这个尺码。我可能有一些拼写错误,因为我正在复制/粘贴/编辑我使用的一些代码,但它应该与我上面定义的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
}