如何在app.config文件中创建嵌套配置部分?错误:"无法识别的属性"

时间:2016-07-21 20:24:06

标签: c# config app-config configsection

我需要创建嵌套配置部分。问题是我需要编写一个访问任意数量的数据库的应用程序。这些可能是oracle,sql或其他任何东西......我想让我的配置部分看起来像这样:

<connectionconfigurations>
    <databaseConnection dbname="connection1" dbsourceConnect="connectionstring1" provider="sql">
      <sqlQueries>
        <add name="querynumber1"
             sqlFilePath="C:\Users\me\Desktop\sql"/>
        <add name="querynumber2"
             sqlFilePath="C:\Users\me\Desktop\sql"/>
      </sqlQueries>
    </databaseConnection>
    <databaseConnection dbname="connection1" dbsourceConnect="connectionstring2" provider="oracle">
      <sqlQueries>
        <add name="querynumber3"
             sqlFilePath="C:\Users\me\Desktop\oracle"/>
        <add name="querynumber4"
             sqlFilePath="C:\Users\me\Desktop\oracle"/>
      </sqlQueries>
    </databaseConnection>
  </connectionconfigurations>

问题是我无法访问所有参数。如何创建这样的嵌套配置部分并通过代码访问它们?

我已经创建了这样一个类来处理连接部分:

public class Connectionconfigurations : ConfigurationSection
    {
        private static ConfigurationPropertyCollection _connectionConfiguration;
        private static ConfigurationPropertyCollection _sqlQueries;
        private static ConfigurationPropertyCollection _properties;



        static Connectionconfigurations()
        {

            _connectionConfiguration = new ConfigurationProperty(
                                       ConfigConstants.CONFIG_DATABASECONNECTION,
                                       typeof(DatabaseConnectionElementCollection),
                                       null,
                                       ConfigurationPropertyOptions.IsRequired);

            _sqlQueries = new ConfigurationProperty(
                         ConfigConstants.CONFIG_SQLQUERIES,
                         typeof(DatabaseConnectionElementCollection),
                         null,
                         ConfigurationPropertyOptions.IsRequired);

            _properties = new ConfigurationPropertyCollection();

            // Add other properties
            _properties.Add(_databaseConnection);
        }

        [ConfigurationProperty("databaseConnection")]
        public DatabaseConnectionElementCollection DatabaseConnection
        {
            get { return (DatabaseConnectionElementCollection)base[_databaseConnection]; }
        }
    }

但是,我收到错误:&#34;无法识别的属性&#39; dbname&#39;。请注意,属性名称区分大小写。&#34;

DatabaseConnectionElement类:

   public class DatabaseConnectionElement : ConfigurationElement
    {

        private static ConfigurationProperty _name;
        private static ConfigurationProperty _sourceConnect;
        private static ConfigurationProperty _provider;
        private static SqlQueryElementCollection _sqlCollection; // Collection of sql queries for this DB element
        private static ConfigurationPropertyCollection _properties;

        static DatabaseConnectionElement()
        {
            _name = new ConfigurationProperty(ConfigConstants.CONFIG_DB_NAME, typeof(string), string.Empty,
                ConfigurationPropertyOptions.IsKey);

            _sourceConnect = new ConfigurationProperty(ConfigConstants.CONFIG_DB_SOURCECONNECT, typeof(string), string.Empty,
                ConfigurationPropertyOptions.IsRequired);

            _provider = new ConfigurationProperty(ConfigConstants.CONFIG_DB_PROVIDER, typeof(string), string.Empty,
                ConfigurationPropertyOptions.IsRequired);

            _sqlCollection = new SqlQueryElementCollection();

            _properties = new ConfigurationPropertyCollection();
            _properties.Add(_name);
            _properties.Add(_sourceConnect);
            _properties.Add(_reconnectDelay);
        }


        [ConfigurationProperty("dbname", IsKey = true)]
        public string Name
        {
            get
            {
                return (string)base[_name];
            }
        }

        [ConfigurationProperty("dbsourceConnect", IsRequired = true)]
        public string SourceConnect
        {
            get
            {
                return (string)base[_sourceConnect];
            }
        }

        [ConfigurationProperty("provider", IsRequired = true)]
        public string Provider
        {
            get
            {
                return (string)base[_provider];
            }
        }

        protected override ConfigurationPropertyCollection Properties
        {
            get
            {
                return _properties;
            }
        }
    }

1 个答案:

答案 0 :(得分:1)

我认为这可能会有所帮助。我创建了一个通用配置部分,其中包含子元素列表。我只是称它们为元素。你可以随意打电话给他们。

/// <summary>
/// Defines a generic custom configuration section with a collection of elements of type T.
/// Reference: http://www.abhisheksur.com/2011/09/writing-custom-configurationsection-to.html
/// </summary>
public class GenericSection<T> : ConfigurationSection
    where T : ConfigurationElement, IConfigurationElement, new()
{

    // Attribute argument must be a constant expression.
    protected const string _elementsTag = "elements";

    public GenericSection()
    {
    }


    [ConfigurationProperty(_elementsTag, Options = ConfigurationPropertyOptions.IsDefaultCollection)]
    public GenericElementCollection<T> Elements
    {
        get { return ((GenericElementCollection<T>)(base[_elementsTag])); }
        set { base[_elementsTag] = value; }
    }

}

这是通用元素集合。

/// <summary>
/// Defines a generic ConfigurationElementCollection
/// </summary>
[ConfigurationCollection(typeof(IConfigurationElement))]
public class GenericElementCollection<T> : ConfigurationElementCollection
    where T : ConfigurationElement, IConfigurationElement, new()
{
    internal const string _elementName = "elements";

    protected override string ElementName
    {
        get { return _elementName; }
    }

    public override ConfigurationElementCollectionType CollectionType
    {
        get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
    }

    protected override bool IsElementName(string elementName)
    {
        return elementName.Equals(_elementName, StringComparison.InvariantCultureIgnoreCase);
    }

    public override bool IsReadOnly()
    {
        return false;
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new T();
    }

    /// <summary>
    /// Return key value for element.
    /// </summary>
    /// <param name="element"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((T)element).Name;
    }

    /// <summary>
    /// Default index property.
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public T this[int index]  // #c160704 was IConfigruationElement
    {
        get { return (T)BaseGet(index); }
    }


    /// <summary>
    /// Returns content element by name.
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public T GetElementByName(string name)
    {
        return (T)BaseGet(name);
    }


    public IEnumerable<T> Elements
    {
        get
        {
            for (int index = 0; index < this.Count; index++) yield return (T)BaseGet(index);
        }
    }

    /// <summary>
    /// Add an element to the collection
    /// </summary>
    /// <param name="element"></param>
    public void AddElement(T element)
    {
        BaseAdd(element);
    }


}

这是我用于Elements的界面。它要求元素具有Name属性和活动标志。

public interface IConfigurationElement
{
    string Name { get; set; }
    bool Active { get; set; }
}

这是一个实例化并使用泛型来创建具有文件夹列表的配置部分的示例。

使用元素类型实例化GenericSection。

/// <summary>
/// Defines a custom configuration section for folder elements.
/// Reference: http://www.abhisheksur.com/2011/09/writing-custom-configurationsection-to.html
/// </summary>
public class FolderSection : GenericSection<FolderElement>
{
    // This section doesn't require any addition properties.
}

我们不需要对GenericElementCollection做任何事情。

这是FolderElement:

/// <summary>
/// Defines a configuration folder
/// </summary>
public class FolderElement : ConfigurationElement, IConfigurationElement
{
    protected const string NameKey = "name";
    protected const string VolumeKey = "volume";
    protected const string PathKey = "path";

    [ConfigurationProperty(NameKey, DefaultValue = "", IsKey = true, IsRequired = true)]
    public string Name
    {
        get { return (string)base[NameKey]; }
        set { base[NameKey] = value; }
    }

    [ConfigurationProperty(VolumeKey, DefaultValue = "", IsKey = false, IsRequired = false)]
    public string VolumeLabel
    {
        get { return (string)base[VolumeKey]; }
        set { base[VolumeKey] = value; }
    }

    [ConfigurationProperty(PathKey, DefaultValue = "", IsKey = false, IsRequired = true)]
    public string Path
    {
        get { return (string)base[PathKey]; }
        set { base[PathKey] = value; }
    }

    [ConfigurationProperty("active", DefaultValue = "true", IsKey = false, IsRequired = false)]
    public bool Active
    {
        get { return (bool)base["active"]; }
        set { base["active"] = value; }
    }
}

这是我的App.config的样子。我有两个文件夹部分。

<configuration>
  <configSections>
    <section name="recent-folders" type="Common.Config.FolderSection, Common.Core"/>
    <section name="hidden-folders" type="Common.Config.FolderSection, Common.Core"/>
  </configSections>
...
  <hidden-folders>
    <elements>
        <add name="folder1" volume="OS" path="C:\some\hidden\path" />
        <add name="folder2" volume="OS" path="C:\some\other\hidden\path" />
    </elements>
  </hidden-folders>
  <recent-folders>
    <elements>
        <add name="folder1" volume="OS" path="C:\Some\path" />
        <add name="folder2" volume="OS" path="C:\Some\other\path" />
    </elements>
  </recent-folders>
</configururation>