这种做法可以参考
http://stackoverflow.com/questions/204695/storing-values-in-the-web-config-appsettings-or-configsection-which-is-more-e
http://haacked.com/archive/2007/03/12/custom-configuration-sections-in-3-easy-steps.aspx
看 以上例子, 发现人家能测试成功, 就是不知道为什么我的例子失败 :-(. anyway, 挫折多点也好, 可以学到更多东西, 特别是对于执着的人.
代码
/// <summary>
/// 自定义配置信息数据结构
/// </summary>
public class UserDefinedDllConfig : ConfigurationSection
{
/// <summary>
///
/// </summary>
public static UserDefinedDllConfig DllSettings
{
get
{
//TODO: 每次调用CurrentDllConfiguration都会再次读取配置文件, 效率低下; 改用Cache
ConfigurationSection cs = CurrentDllConfiguration.GetSection(FullSectionName);
// 或者CurrentDllConfiguration.GetSectionGroup(SectionGroupName).Sections[SectionName]
return cs as UserDefinedDllConfig;//转换后为null
}
}
/// <summary>
/// 数据库名
/// </summary>
[ConfigurationProperty("DATABASE_NAME", IsRequired = true)]
public string DatabaseName
{
get
{
return this["DATABASE_NAME"] as string;
}
}
/// <summary>
/// 本系统名称
/// </summary>
[ConfigurationProperty("APPLICATION_NAME", IsRequired = true)]
public string ApplicationName
{
get
{
return this["APPLICATION_NAME"] as string;
}
}
}
2.5 Configuration类型转换为ClientSettingsSection类型的情况
经过以上测试, 用google查找很多关于dll.config的设置文件读取的资料, 发现有例子将配置信息类型Configuration转换为ClientSettingsSection操作. 但是我测试发现还是有问题, 下面是代码:
代码
/// <summary>
/// 内置转换为ClientSettingsSection类型
/// 不提示错误而且转换后也不为null, 但调用 .Settings["APPLICATION_NAME"] 提示:
/// 错误 “System.Configuration.ConfigurationElement.this[System.Configuration.ConfigurationProperty]”不可访问,因为它受保护级别限制
/// </summary>
public static ClientSettingsSection DllSettings_ClientSettingsSection
{
get
{
ConfigurationSection cs = CurrentDllConfiguration.GetSection(FullSectionName);
return cs as ClientSettingsSection;
}
}不提示错误而且转换后也不为null, 但调用 .Settings["APPLICATION_NAME"] 提示:
错误 “System.Configuration.ConfigurationElement.this[System.Configuration.ConfigurationProperty]”不可访问,因为它受保护级别限制
这个错误很郁闷, 因为遇到很多次, 上次就是AppSettings["参数名"], 改为AppSettings.Settings["参数名"].Value就可以, 但是这里不行. 还是会有错误. 到这里, 再次查找很多资料, 发现不少老外也遇到这个问题没解决. 今天一个偶然机会, 看到帖子:
http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/ec237df4-f05e-4711-a230-fb089c395c73/?prof=required
(根据微软网站以往的情况, 这个链接很可能以后会改变...)
OK. 下面就提出这个帖子中提到的3种可行的解决方案.
2.6 参考上面帖子nrolland的回复
接着2.5的问题,
转换为ClientSettingsSection类型后, 采用以下方式可以读取出数据:
System.Console.WriteLine(TestDllConfig.DllConfig.DllSettings_ClientSettingsSection.Settings.Get("APPLICATION_NAME").Value.ValueXml.InnerText);
很显然, 这种方案在类似ConfigurationManager的方式下调用, 但是还是有很明显的XML操作痕迹. 没办法, XML才是老本根, 谁叫设置文件采用xml格式呢.
2.7 经典的XML解决方案
上面的帖子回帖中就有人写了一段代码: (下面这段基本上是直接手工照敲一遍, 就是处理叶子节点稍微修改了下, 因为配置文件不一样嘛)
代码
/// <summary>
/// 通过Xml处理取得配置信息
/// </summary>
/// <param name="sSection"></param>
/// <param name="sFilePath"></param>
/// <returns></returns>
private static NameValueCollection GetNameValueCollectionSection(string sSection, string sFilePath)
{
string sFile = sFilePath;
System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
NameValueCollection nRet = new NameValueCollection();
try
{
ExeConfigurationFileMap fMap = new ExeConfigurationFileMap();
fMap.ExeConfigFilename = sFile;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fMap, ConfigurationUserLevel.None);
string sXml = config.GetSection(sSection).SectionInformation.GetRawXml();
xDoc.LoadXml(sXml);
}
catch (Exception exp)
{
throw new Exception(exp.Message);
}
System.Xml.XmlNode xList = xDoc.ChildNodes[0];
//System.Xml.XmlNode xList = xDoc.GetElementsByTagName(SectionName)[0];
foreach (System.Xml.XmlNode xNode in xList)
{
//nRet.Add(xNode.Attributes[0].Value, xNode.Attributes[1].Value);
//NOTE: Test.settings自动生成的xml格式与<appSettings>不一样: Value在子节点
nRet.Add(xNode.Attributes[0].Value, xNode.ChildNodes[0].ChildNodes[0].Value);
}
return nRet;
}网上类似的代码很多. 就是基本的XML操作, 加上ConfigurationManager.
通过调用 return GetNameValueCollectionSection(FullSectionName, DllConfigFilePath); 直接返回NameValueCollection类型数据, 得到NameValueCollection类型数据就没问题了.
这里补充说明下为什么开头会将获取dll.config文件的路径的方法封装一遍, 因为写这段代码的时候直接照敲, 结果发现用Assembly读取到的配置文件路径不一样. 查MSDN发现:
Assembly.GetCallingAssembly返回调用当前正在执行的方法的方法的 Assembly。
这就是基础不扎实的表现...
2.8 从自动生成的代码中读取配置的情况
上面帖子最后一篇(当前时间20100301是最后一篇)提到另外一种解决思路. 参考网址: http://www.codeproject.com/KB/cs/UserSettings.aspx. 这篇文章开头的截图是不是很像呢? 哈, 自动生成配置文件基本操作都差不多.
还记得不? 开始设置参数后自动生成的那个cs文件吗? 自动生成的代码一看就明白.
代码
#region 从自动生成的代码中读取配置的情况
/// <summary>
/// 可以通过以下方式给外部调用
/// </summary>
public static string m_DllSettings_By_AutoGenerated = TestDllConfig.Test.Default.DATABASE_NAME;
/// <summary>
/// 从自动生成的代码中读取(有默认值)
/// NOTE: 如果声明为public或protected, 会编译错误:
/// 错误 23 可访问性不一致: 属性类型“TestDllConfig.Test”比属性“TestDllConfig.DllConfig.DllSettings_By_AutoGenerated”的可访问性低
/// 所以只能声明为private.
/// 但是TestDllConfig.Test.Default.DATABASE_NAME却可以访问
/// NOTE2: 有时候自动生成的cs文件可能会丢失, 或者删除. 因此这种方法必须要求自动生成的代码存在.
/// </summary>
private static Test DllSettings_By_AutoGenerated
{
get
{
return TestDllConfig.Test.Default;
}
}
#endregion除了要留意自动生成的类是sealed类型, 需要通过类似
public static string m_DllSettings_By_AutoGenerated = TestDllConfig.Test.Default.DATABASE_NAME;
的方式给外部程序调用(就是测试用的控制台程序, 如果是类库自身调用问题就不大了)
3. 小结
本文从头到尾记录了本人对这个问题的思考过程. 或许还有更加完美的解决方案, 希望园子里的大牛们不吝赐教. 文章写的有点啰嗦了, 记录下来也是为了以后自己查找资料方便. 希望这篇文章对有需要的朋友有用. 欢迎各位针对本文提出意见(不希望见到匿名谩骂)
总的来说, 我还是偏向于2.6的解决方案, 比较方便, 而且不容易出错(通过参数名来读取值, 而不是索引);
自动生成的代码是可以删除的, 某些情况下也可能丢失, 所以不是很可靠, 如果是需要从cs文件中读取配置信息, 那又何必搞多个配置文件呢? 我的原始目的就是为了不用再次编译引入配置文件的嘛. 也是可以从设置文件读数据, 而且可以有默认值
另外, 对于为一个dll文件是否有必要添加设置文件,
http://stackoverflow.com/questions/594298/c-dll-config-file
这里的最好的答复有说明(太长了, 没看完...)
最后, 附上本文的测试源代码:/Files/GuominQiu/SourceCode/20100301_TestDllConfig_SourceCode.7z
PS. 再啰嗦一句, 采用7-ZIP格式压缩源代码, 可以比winrar得到更加高的压缩率, 对比相当明显. 一般一个50M以上的项目源代码目录, 用7zip可以压缩到大约6M多点.