有經驗的開發人員都知道在開發.NET應用時可以利用配置檔案儲存一些常用并且有可能變化的資訊,例如日志檔案的儲存路徑、資料庫連接配接資訊等等,這樣即使生産環境中的參數資訊與開發環境不一緻也隻需要更改配置檔案而不用改動源代碼再重新編譯,極其友善。并且我們一般還約定,在<appSettings>節點儲存應用程式的配置資訊,在<connectionStrings>中儲存資料庫連接配接字元串資訊(詳見本部落格《ASP.NET夜話之十一》)。
上面的這些方法和約定足以讓我們在大部分開發中獲得友善,但是在有些情況下有些配置資訊可以按組分類存放,如果采用上面的方法不僅不直覺,而且讀取起來也不是太友善,幸好在.NET裡就提供了這樣的方法。如果有使用過Log4Net或者Enyim.Caching的朋友,肯定對下面的配置不會陌生:
<sectionGroup name="enyim.com"><section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" /></sectionGroup>
或:
<configSections><section name="log4net" type="System.Configuration.IgnoreSectionHandler"/></configSections>
在出現上面配置的配置檔案中,我們就會找到名稱為"enyim.com"或者"log4net"的節點,盡管它們本不屬于config檔案的預設節點,但是通過上面的配置之後程式運作并不會報錯。這樣一來,相關配置資訊也可以很好分類儲存起來。
在這裡周公示範一個簡單的例子,這個例子來源于周公的一個從2006年起就開始開發的自用軟體(因為沒有美化是以沒有免費釋出),在這個應用程式的connfig檔案中我增加了一些特有的配置,是以新增了一個自己的節點,app.config檔案内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="SoftwareSettings" type="ImageAssistant.Configuration.SoftwareSettings, ImageAssistant" />
</configSections>
<SoftwareSettings>
<LoadSettings>
<add key="LoadBmp" value="true"/>
<add key="LoadJpg" value="true"/>
<add key="LoadGif" value="true"/>
<add key="LoadPng" value="false"/>
</LoadSettings>
<PathSettings SavePath="C:\ResizeImages\" SearchSubPath="true"/>
</SoftwareSettings>
<appSettings>
<add key="LoadBmp" value="true"/>
<add key="LoadJpg" value="true"/>
<add key="LoadGif" value="true"/>
<add key="LoadPng" value="false"/>
<add key="IncludeSubPath" value="true"/>
</appSettings>
</configuration>
在config檔案中我們使用<section name="SoftwareSettings" type="ImageAssistant.Configuration.SoftwareSettings, ImageAssistant" />告訴應用程式對于配置檔案中的SoftwareSettings節點,其對應的類是ImageAssistant程式集中ImageAssistant.Configuration.SoftwareSettings類,并且在<SoftwareSettings>節點中我們還看到有<LoadSettings>節點和<PathSettings>節點,其中<LoadSettings>是一個節點集合,還包含有多個子節點,為了表示清楚這些關系我們需要添加四個類:SoftwareSettings、LoadSettingsCollection、LoadSettingsElement及PathSettingElement。為了釋出友善,周公将這四個類的代碼放在一個實體檔案中,代碼如下(注意添加對System.Configuration.dll的引用):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
//作者:zhoufoxcn(周公)
//日期:2011-03-08
//blog:http://blog.csdn.net/zhoufoxcn 或http://zhoufoxcn.blog.51cto.com
//版權聲明:本文允許非商業用途,但必須保證不得去掉本文中的任何連結,違者必究。
namespace ImageAssistant.Configuration
{
public sealed class LoadSettingsCollection : ConfigurationElementCollection
{
private IDictionary<string, bool> settings;
protected override ConfigurationElement CreateNewElement()
{
return new LoadSettingsElement();
}
protected override object GetElementKey(ConfigurationElement element)
LoadSettingsElement ep = (LoadSettingsElement)element;
return ep.Key;
protected override string ElementName
get
{
return base.ElementName;
}
public IDictionary<string, bool> Settings
if (settings == null)
{
settings = new Dictionary<string, bool>();
foreach (LoadSettingsElement e in this)
{
settings.Add(e.Key, e.Value);
}
}
return settings;
public bool this[string key]
bool isLoad = true;
if (settings.TryGetValue(key, out isLoad))
return isLoad;
else
throw new ArgumentException("沒有對'" + key + "'節點進行配置。");
}
public class LoadSettingsElement : ConfigurationElement
[ConfigurationProperty("key", IsRequired = true)]
public string Key
get { return (string)base["key"]; }
set { base["key"] = value; }
[ConfigurationProperty("value", IsRequired = true)]
public bool Value
get { return (bool)base["value"]; }
set { base["value"] = value; }
public class PathSettingElement : ConfigurationElement
/// <summary>
///
/// </summary>
[ConfigurationProperty("SavePath", IsRequired = true)]
public string SavePath
get { return (string)base["SavePath"]; }
set { base["SavePath"] = value; }
[ConfigurationProperty("SearchSubPath", IsRequired = false, DefaultValue = true)]
public bool SearchSubPath
get { return (bool)base["SearchSubPath"]; }
set { base["SearchSubPath"] = value; }
/// <summary>
/// 對應config檔案中的
/// </summary>
public sealed class SoftwareSettings : ConfigurationSection
/// 對應SoftwareSettings節點下的LoadSettings子節點
[ConfigurationProperty("LoadSettings", IsRequired = true)]
public LoadSettingsCollection LoadSettings
get { return (LoadSettingsCollection)base["LoadSettings"]; }
/// 對應SoftwareSettings節點下的PathSettings子節點,非必須
[ConfigurationProperty("PathSettings", IsRequired = false)]
public PathSettingElement PathSetting
get { return (PathSettingElement)base["PathSettings"]; }
set { base["PathSettings"] = value; }
}
在上面的代碼中可以看到ConfigurationProperty這個屬性,這是表示對應的屬性在config檔案中的屬性名,IsRequired表示是否是必須的屬性,還有DefaultValue表示屬性的預設值。初次之外,我們還要注意以下關系:
SoftwareSettings:根節點,繼承自ConfigurationSection。
LoadSettingsCollection:子節點集合,繼承自ConfigurationElementCollection。
LoadSettingsElement:子節點,繼承自ConfigurationElement。
PathSettingElement:子節點,繼承自ConfigurationElement。
編寫了如下代碼之後,我們又該如何使用上面的類呢?其實很簡單,如下:
class Program
static void Main(string[] args)
SoftwareSettings softSettings = ConfigurationManager.GetSection("SoftwareSettings") as SoftwareSettings;
foreach (string key in softSettings.LoadSettings.Settings.Keys)
Console.WriteLine("{0}={1}", key, softSettings.LoadSettings[key]);
Console.WriteLine("SavePath={0},SearchSubPath={1}", softSettings.PathSetting.SavePath, softSettings.PathSetting.SearchSubPath);
Console.ReadLine();
}
這個程式的運作結果如下:
LoadBmp=True
LoadJpg=True
LoadGif=True
LoadPng=False
SavePath=C:\ResizeImages\,SearchSubPath=True
總結:在上面的config檔案中通過<appSettings>也達到了類似的效果,但是通過自定義節點我們可以友善地讀取相關的應用程式配置,同時也便于維護。如果在開發過程中遇到本文中類似的情況,不妨采取本文所述的方式。附件是本文中所用的源代碼。
本文轉自周金橋51CTO部落格,原文連結: http://blog.51cto.com/zhoufoxcn/510371,如需轉載請自行聯系原作者