【问题标题】:How to specify a collection in a custom configSection如何在自定义 configSection 中指定集合
【发布时间】:2010-01-04 22:25:16
【问题描述】:

我想要一个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 是我目前所拥有的,但它并不完全正确

【问题讨论】:

    标签: .net configuration configuration-files


    【解决方案1】:

    如果 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;
                }
            }
        }
    }
    

    要访问它,这段代码 sn-p 应该会有所帮助:

            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();
    

    基本上我们有一个处理插件元素的配置部分。在此,我们指定一个 ConfigurationElementCollection 属性并将其声明为默认集合(理论上您可以在一个根节点下拥有多个不同的集合)。

    PluginsElementCollection 实现了 ConfigurationElementCollection。 ElementName 必须是标签的名称,在我们的例子中是“use”。此外,GetElementKey 需要被覆盖,并且应该返回一个在条目中唯一的属性。

    PluginsElement 然后实现单次使用标签。我们只定义了一个属性:AssemblyName,它映射到了assembly-attribute。

    我并没有声称完全理解所有这些(特别是 ConfigurationElementCollection 以及它的各种 BaseAdd、BaseGet 等属性,这里并没有真正探索),但我可以声称这是可行的 :)

    另外,它不使用任何属性。我讨厌属性——幸运的是,所有这些属性都可以转换为正确的代码。您可以使用其中一个(或两者)。

    【讨论】:

    • 另外,如果您愿意,请查看 System.Web.Configuration.CustomErrorsSection 和其他使用 Reflector 或调试服务器的人。看看微软如何实现这些(恕我直言相当复杂)类可以提供很好的洞察力。
    【解决方案2】:

    根据本教程,您可以轻松创建 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
    }
    

    【讨论】:

    • 我不确定如何在本教程中做到这一点。你需要某种中间元素(比如教程有“动作”)
    • 在这种方法中,您应该能够使用内部 NameValueSectionHandler:msdn.microsoft.com/en-us/library/… - 抱歉,不知道具体方法(老实说,我会自己动手),但谷歌会在这里提供帮助:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-11
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    • 2011-09-22
    相关资源
    最近更新 更多