在C#类库中使用App.config文件自定义配置

  • Post author:
  • Post category:其他


做项目时,经常需要在自己设计的类库中使用很多用户配置。虽然在应用程序的App.config和Web应用程序web.config这样的文件里配置也能满足需求,但这样做不仅会让主配置文件的内容变得多、杂,还会让模块依赖主程序的配置文件。

我们知道在VS中,可以在类库项目里添加一种叫做“应用程序配置文件”的文件,这是标准的.NET配置文件,模板自带“configuration”元素,编辑时还会有智能提示。但是怎么在程序代码中使用写在App.config里的配置呢?近日在网上搜了一通,却一无所获。于是只好自已动手!

我以前做的一个项目里,用到过类型的实现方式。可以获取在类库App.config文件中“appSettings”和“conectionStrings”节添加的自定义配置,但是不能自定义配置节。从MSDN上了解到,要想在配置文件中自定义配置节,需要实现一个自定义的ConfigurationSection。两下结合起来,想在类库中用App.config彻底自定义配置的需求就可以实现了。

现在分享出来,希望对看到这篇文章的朋友有所帮助。


第一步:创建项目和类库:

新建一个Windows控制台应用程序“MyDemo”,然后再新建一个C#类库“MyDemo.Config”,并在MyDemo中添加对MyDemo.Config的引用。


第二步:添加引用,新建配置文件:

在MyDemo.Config中先删除除System之外的所有引用,然后添加对System.Configuration库的引用,并新建一个配置文件App.config。


第三步:在MyDemo.Config里面添加一个静态类“ConfigManager”

,代码里这样写:

using System;
using System.Configuration;

namespace MyDemo.Config
{
    public static class ConfigManager
    {
        readonly static bool _Error;

        static Configuration _AppConfig;

        static ConfigManager()
        {
            string dllPath = string.Format(
                "{0}\\{1}.dll", AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory, "MyDemo.Config");

            try
            {
                _AppConfig = ConfigurationManager.OpenExeConfiguration(dllPath);
            }
            catch(ConfigurationErrorsException)
            {
                _Error = true;
            }
        }

        public static KeyValueConfigurationCollection AppSettings
        {
            get 
            {
                if (_Error) return null;
                return _AppConfig.AppSettings.Settings;
            }
        }

        public static ConnectionStringSettingsCollection ConnectionStrings
        {
            get
            {
                if (_Error) return null;
                return _AppConfig.ConnectionStrings.ConnectionStrings;
            }
        }
    }
}

通过AppDomain.CurrentDomain.BaseDirectory和稳定的类库名称,来获取实际运行中该dll文件的具体物理路径,然后通过ConfigurationManager的OpenExeConfiguration方法就能获取到相应的dll.config文件中的配置。

为了保险起见,我增加了一个_Error字段,在静态构造器中使用了try语句,这样能保证程序的顺序运行!

通过这个ConfigManager,可以直接获取在App.config中添加的appSeetings和connectionStrings的配置。


第四步:添加对自定义的配置节的支持

要自定义配置节,需要实现ConfigurationSection。这个其实MSDN上就有很好的例子,我这里做一个简单的实现,比如我要增加这样的配置:

<smtp host="smtp.163.com" mail="abc@163.com" pass="123456"></smtp>

我们来新建一个SmtpSection,继承自ConfigurationSection。重写基类的IsReadOnly()方法,表示这些配置是只读的。

然后我们添加几个只读的属性:Host(string)、Mail(string)、Password(string)、Port(int);get访问器的实现很特殊,要用this[“自定义配置节的attribute名称”]这种方法,还要转换成相应属性的具体类型。所有将在配置中出现的属性,都要加上ConfigurationProperty标记。

来看具体的实现:

using System;
using System.Configuration;

namespace MyDemo.Config
{
    public class SmtpSection : ConfigurationSection
    {
        public override bool IsReadOnly()
        {
            return true;
        }

        [ConfigurationProperty("host", IsRequired = true)]
        public string Host
        {
            get { return this["host"] as string; }
        }

        [ConfigurationProperty("mail", IsRequired = true)]
        //[RegexStringValidator(可以在这里用正则验证配置文件中的值是否正确)]
        public string Mail
        {
            get { return this["mail"] as string; }
        }

        [ConfigurationProperty("pass", IsRequired = true)]
        public string Password
        {
            get { return this["pass"] as string; }
        }

        [ConfigurationProperty("port", IsRequired = false, DefaultValue = 25)]
        [IntegerValidator(MaxValue = 65535, MinValue = 1)]
        public int Port
        {
            get { return (int)this["port"]; }
        }
    }
}

可以看到,在声明属性的ConfigurationProperty标记时,不但可以指定此属性将在配置文件中出现的的名称,还可以指定默认值、是否必须属性等。字符串还可以使用RegexStringValidator标记来验证用户输入的配置是否合法;数字则可以用IntegerValidator来规定用户输入的数字范围。最贴心的是这些合法性的验证,都是在编译时进行的,而不是在程序运行时。


第五步:在App.Config中添加自定义配置节

新增一个configSections节,在下面添加自定义的section,nam的值是下面的xml元素的开始和结束标记,type的值的格式是这样的“自定义配置节类型的完全名称(包括命名空间), 命名空间”。这里增加一个appSetting和connectionString以便稍后测试。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="smtp" type="MyDemo.Config.SmtpSection, MyDemo.Config" />
  </configSections>
  <smtp host="smtp.163.com" mail="abc@163.com" pass="123456"></smtp>
  <appSettings>
    <add key="domain" value="dream.net" />
  </appSettings>
  <connectionStrings>
    <add name="default" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|NORTHWND.MDF;Integrated Security=True;Connect Timeout=30" />
  </connectionStrings>
</configuration>


第六步:修改ConfigManager,添加获取自定义配置节smtp的方法

给ConfigManager类增加一个方法,为了能最大限度的重用这个方法,我把方法写成了泛型方法! GetSection<T>(string name);

    public static T GetSection<T>(string name) where T : ConfigurationSection
    {
        if (_Error) return null;
        return _AppConfig.GetSection(name) as T;
    }


第七步:测试

要想使这个配置起使用,前提是App.config文件必须以“dll名称.dll.config”的文件名存在应用程序的执行目录中。生成类库的时候,在类库的输出目录会自动生成这个配置文件,但是每次更新配置文件都要把配置文件复制一遍很麻烦。解决办法就是,把App.config改名。比如上面提到的MyDemo.Config中的App.config就可以改成“MyDemo.Config.dll.config”,然后设置属性“复制到输出目录”为“较新则复制”。这样,每次修改配置文件后,只要重新生成,配置文件就会被自动复制到应用程序的执行目录中。

解决了这个问题,我们在MyDemo中写一段代码测试一下,因为ConfigManager的一些属性和方法的返回值的类型位于System.Configuration命名空间,所以,要使用它必须在程序中也添加对System.Configuration的引用。当然,你也可以改变一下获取appSettings和connectionStrings的方式,直接返回配置的值,而不是配置集合!

using MyDemo.Config;    
class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(ConfigManager.AppSettings["domain"].Value);
            Console.WriteLine(ConfigManager.ConnectionStrings["default"].ConnectionString);
            var smtp = ConfigManager.GetSection<MyDemo.Config.SmtpSection>("smtp");
            Console.WriteLine(smtp.Host);
            Console.WriteLine(smtp.Mail);
            Console.WriteLine(smtp.Password);
            Console.WriteLine(smtp.Port);

            Console.Read();
        }
    }

运行结果:

通过结果,可以确定配置在config里面的设置都已经被顺利的读出来了;这是ConfigurationSection的实现,另外,如果要实现的配置具有复杂数据结构,还要根据需要实现ConfigurationElement,具体实现请参考MSDN的例子

http://msdn.microsoft.com/zh-cn/library/2tw134k3(v=vs.100).aspx

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

PS:可以对例子的ConfigManager做一些改造,使之成为项目配置存取模块(Configuration是支持读写的)。另外,对于一些不想这么麻烦的懒人,我推荐一款免费的VS插件,叫“Configuration Section Designer”,安装插件后会安装一个配置节的设计模板,允许你像设计UML图一样设计你的配置,插件会帮你自动生成具体的实现,非常的实用。

http://www.cnblogs.com/shalves/archive/2013/03/11/use_appconfig_on_csharp_library.html