今天做一个windows插件式服务程序,插件有时要读取配置文件的设置,但是服务是动态加载到服务上的,没有办法作到动态修改服务的配置文件(app.config)。在.net 2.0中有一个ConfigurationManager类可以方面的读取默认的配置文件,如果要自定义读取配置文件,这个类也提供了方法,如下所示:
var configMap = new ExeConfigurationFileMap { ExeConfigFilename = configFile }; var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None); var configurationSection = config.GetSection(sectionName);
这种获取到的对象只是这个Section的名称和xml内容,这和ConfigurationManager默认方法GetSection获取到的是一个对象,可以进行强制转换成相应的类型相比,十分的不方便。
在不想造轮子想法,在google中搜索了很久也没有找到好的解决方法。最后,还是自己研究解决。
在上面的对象“configurationSection”是一个DefaultSection的类型,它有一个属性SectionInformation,如下所示:
public System.Configuration.SectionInformation SectionInformation { get; }
这个属性包含了从配置文件中读取到的xml信息,其中这个类型一个关键方法:
public string GetRawXml()
用于获取配置中的xml内容,举例如下:
有如下配置文件:
1:
2:
3:"WeiboClientSectionGroup">
4:"SinaSection" type="System.Configuration.NameValueSectionHandler,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
5:"QQSection" type="System.Configuration.NameValueSectionHandler,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
6:"SohuSection" type="System.Configuration.NameValueSectionHandler,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
7:"NetEaseSection" type="System.Configuration.NameValueSectionHandler,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
8:
9:"WeiboSectionGroup">
10:"SinaSection" type="System.Configuration.NameValueSectionHandler,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
11:"QQSection" type="System.Configuration.NameValueSectionHandler,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
12:"SohuSection" type="System.Configuration.NameValueSectionHandler,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
13:"NetEaseSection" type="System.Configuration.NameValueSectionHandler,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
14:
15:
16:
17:
18:"AccessToken" value=""/>
19:"AccessTokenSecret" value=""/>
20:"ResultFormat" value="Json"/>
21:
22:
27:
28:"AccessToken" value=""/>
29:"AccessTokenSecret" value=""/>
30:"ResultFormat" value="Json"/>
31:
32:
33:
34:"AccessToken" value=""/>
35:"AccessTokenSecret" value=""/>
36:"ResultFormat" value="Json"/>
37:
38:
39:"AccessToken" value=""/>
40:"AccessTokenSecret" value=""/>
41:"ResultFormat" value="Json"/>
42:
43:
44:
45:
46:"AppKey" value=""/>
47:"AppSecret" value=""/>
48:"AuthorizeUri" value="http://api.t.sina.com.cn/oauth/authorize"/>
49:"RequestTokenUri" value="http://api.t.sina.com.cn/oauth/request_token"/>
50:"AccessTokenUri" value="http://api.t.sina.com.cn/oauth/access_token"/>
51:"CallBackUri" value="null">
52:
53:
54:"AppKey" value=""/>
55:"AppSecret" value=""/>
56:"AuthorizeUri" value="https://open.t.qq.com/cgi-bin/authorize"/>
57:"RequestTokenUri" value="https://open.t.qq.com/cgi-bin/request_token"/>
58:"AccessTokenUri" value="https://open.t.qq.com/cgi-bin/access_token"/>
59:"CallBackUri" value="null">
60:
61:
62:"AppKey" value=""/>
63:"AppSecret" value=""/>
64:"AuthorizeUri" value="http://api.t.sohu.com/oauth/authorize"/>
65:"RequestTokenUri" value="http://api.t.sohu.com/oauth/request_token"/>
66:"AccessTokenUri" value="http://api.t.sohu.com/oauth/access_token"/>
67:"CallBackUri" value="null">
68:
69:
70:"AppKey" value=""/>
71:"AppSecret" value=""/>
72:"AuthorizeUri" value="http://api.t.163.com/oauth/authenticate"/>
73:"RequestTokenUri" value="http://api.t.163.com/oauth/request_token"/>
74:"AccessTokenUri" value="http://api.t.163.com/oauth/access_token"/>
75:"CallBackUri" value="null">
76:
77:
78:"v4.0" sku=".NETFramework,Version=v4.0"/>
我们sectionName=”WeiboSectionGroup/SinaSection”
上面的函数就返回如下字符串:
<SinaSection> <add key="AppKey" value=""/> <add key="AppSecret" value=""/> <add key="AuthorizeUri" value="http://api.t.sina.com.cn/oauth/authorize"/> <add key="RequestTokenUri" value="http://api.t.sina.com.cn/oauth/request_token"/> <add key="AccessTokenUri" value="http://api.t.sina.com.cn/oauth/access_token"/> <add key="CallBackUri" value="null">add> SinaSection>
另外此类型,还有一个Type属性,是字符串类型,如上面的配置,读取出来就是“
System.Configuration.NameValueSectionHandler,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
”
根据上面的信息,我们就可以首先使用反射的方式,生成对象NameValueSectionHandler,现调用此对的Create方法进行创建NameValueCollection,如下所示:
private static TReturn LoadSection(SectionInformation information) where TReturn:class { string[] strs = information.Type.Split(",".ToCharArray(), 2); var handler = (IConfigurationSectionHandler)Assembly.Load(strs[1]).CreateInstance(strs[0]); var doc = new XmlDocument(); doc.LoadXml(information.GetRawXml()); if (handler != null) return (TReturn)handler.Create(null, null, doc.ChildNodes[0]); return null; }
下面提供一个完整的实例:
1: public abstract class ConfigBasewhere T:class
2: {
3: protected ConfigBase(string sectionName, string configFile)
4: {
5: if (string.IsNullOrEmpty(configFile))
6: {
7: Section = (T)ConfigurationManager.GetSection(sectionName);
8: }
9: else
10: {
11: var configMap = new ExeConfigurationFileMap { ExeConfigFilename = configFile };
12: var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
13: var configurationSection = config.GetSection(sectionName);
14: if (configurationSection != null)
15: {
16: Section = LoadSection(configurationSection.SectionInformation);
17: }
18: }
19: }
20:
21: private static TReturn LoadSection(SectionInformation information) where TReturn:class
22: {
23: string[] strs = information.Type.Split(",".ToCharArray(), 2);
24: var handler = (IConfigurationSectionHandler)Assembly.Load(strs[1]).CreateInstance(strs[0]);
25: var doc = new XmlDocument();
26: doc.LoadXml(information.GetRawXml());
27: if (handler != null)
28: return (TReturn)handler.Create(null, null, doc.ChildNodes[0]);
29: return null;
30: }
31:
32: protected T LoadSection(SectionInformation information)
33: {
34: return LoadSection(information);
35: }
36:
37: protected T Section { get; private set; }
38: }
上面是一个抽象类,从上面的类进行继承,就可以实现功能,如下所示:
1: public class ClientConfig : ConfigBase
2: {
3: public ClientConfig(WeiboType weiboType)
4: : this(weiboType, null)
5: {
6: }
7:
8: public ClientConfig(WeiboType weiboType, string configFile)
9: : base(string.Format("WeiboClientSectionGroup/{0}Section", weiboType), configFile)
10: {
11: }
12:
13: public string AccessToken
14: {
15: get { return Section["AccessToken"]; }
16: }
17:
18: public string AccessTokenSecret
19: {
20: get { return Section["AccessTokenSecret"]; }
21: }
22:
23: public ResultFormat ResultFormat
24: {
25: get { return (ResultFormat)Enum.Parse(typeof(ResultFormat), Section["ResultFormat"]); }
26: }
27: }