在大型項目開發中,我們需要配置各種各樣的信息。比如:在線支付方式有支付寶,網銀,財付通,快錢。我們需要配置支付寶賬號信息,需要配置財付通賬號信息,需要配置網銀賬號信息還有快錢賬號信息。發郵件呢?我們需要配置郵件服務器信息。發短信呢?我們需要配置短息服務器信息。對於各種各樣形形色色的配置信息,我們該如何配置呢?又該如何才能方便管理呢?我先介紹下.Net自帶的配置信息類,然後在使用反射技術自定義一個配置管理類。
1)使用System.Configuration.AppSettingsSection類
.Net已經提供了AppSettingsSection類方便我們配置信息。我們可以把配置信息放在Web.confg或App.config的appSettings節點下。如下:
<configuration>
<appSettings>
<!--支付寶合作身份者Id-->
<add key="AlipayId" value="1234567890"/>
<add key="AlipayKey" value="test1234567890"/>
<add key="AlipayEmail" value="[email protected]"/>
<!--財付通商戶號-->
<add key="TenpayId" value="1234567890"></add>
<!--財付通密鑰-->
<add key="TenpayKey" value="test1234567890"/>
<!--網銀商戶號-->
<add key="ChinaBankId" value="1001"></add>
<!--網銀密鑰-->
<add key="ChinaBankKey" value="test"/>
</appSettings>
</configuration>
這種配置方式是最基本的配置方式,也是我們最常用的配置方式,但這樣的配置方式顯然不能讓我們滿意。因為大量的配置信息放在一起,即無法對信息進行分組,也不方便管理,時間一長,我們自己可能已經不記得配置信息的意思,而且修改任何的配置內容都會導致Asp.Net站點重新啟動。
2)使用System.Configuration.NameValueSectionHandler類
.Net在System下提供NameValueSectionHandler類可以對配置信息進行方便的分組。NameValueSectionHandler類的定義是這樣的:
NameValueSectionHandler : IConfigurationSectionHandler { string defaultKeyAttribute = ; string defaultValueAttribute = ; [TargetedPatchingOptOut()] NameValueSectionHandler(); object Create(object parent, object context, XmlNode section); object CreateStatic(object parent, XmlNode section); object CreateStatic(object parent, XmlNode section, string keyAttriuteName, string valueAttributeName); string KeyAttributeName { ; } string ValueAttributeName { ; } }
NameValueSectionHandler類實現了接口IConfigurationSectionHandler的Create方法,返回一個ReadOnlyNameValueCollection
object CreateStatic(object parent, XmlNode section, string keyAttriuteName, string valueAttributeName) { ReadOnlyNameValueCollection values; (parent == ) { values = ReadOnlyNameValueCollection(StringComparer.OrdinalIgnoreCase); } { ReadOnlyNameValueCollection values2 = (ReadOnlyNameValueCollection) parent; values = ReadOnlyNameValueCollection(values2); } HandlerBase.CheckForUnrecognizedAttributes(section); (XmlNode node section.ChildNodes) { (!HandlerBase.IsIgnorableAlsoCheckForNonElement(node)) { (node.Name == ) { string str = HandlerBase.RemoveRequiredAttribute(node, keyAttriuteName); string str2 = HandlerBase.RemoveRequiredAttribute(node, valueAttributeName, ); HandlerBase.CheckForUnrecognizedAttributes(node); values[str] = str2; } { (node.Name == ) { string name = HandlerBase.RemoveRequiredAttribute(node, keyAttriuteName); HandlerBase.CheckForUnrecognizedAttributes(node); values.Remove(name); ; } (node.Name.Equals()) { HandlerBase.CheckForUnrecognizedAttributes(node); values.Clear(); ; } HandlerBase.ThrowUnrecognizedElement(node); } } } values.SetReadOnly(); values; }從代碼中,可以看出需要一個Add節點,該節點包含一個Key和Value的屬性。我們可以這樣配置各種信息。
<configuration>
<configSections>
<section name="Alipay" type="System.Configuration.NameValueSectionHandler"/>
<section name="TenPay" type="System.Configuration.NameValueSectionHandler"/>
<section name="WebBank" type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<Alipay>
<!--合作身份者ID-->
<add key="Id" value="1234567890" />
<!--安全檢驗碼-->
<add key="key" value="test1234567890" />
<add key="email" value="[email protected]" />
</Alipay>
<TenPay>
<!--合作身份者ID-->
<add key="Id" value="1234567890" />
<!--安全檢驗碼-->
<add key="key" value="test1234567890" />
</TenPay>
<WebBank>
<!--合作身份者ID-->
<add key="Id" value="1001" />
<!--安全檢驗碼-->
<add key="key" value="test1234567890" />
</WebBank>
</configuration>
可以這樣讀取配置信息:
//支付寶配置信息
var alipays = (NameValueCollection)ConfigurationManager.GetSection("Alipay");
//支付寶Id
string alipayId = alipays["Id"];
//支付寶Key
string alipaykey = alipays["key"];
這種配置方式可以有效的對各種不同的配置信息進行分組,方便查看和修改。但不符合面向對象的開發,也無法對配置的信息進行類型檢查,修改配置信息一樣會導致Asp.Net站點重新啟動。
3)自定義配置節點
我們可以仿照AppSettingsSection類的實現方式,自定義節點配置類。可以繼承ConfigurationSection類實現自定義節點配置類。
public class AlipaySetion : ConfigurationSection
{
[ConfigurationProperty("Id", IsKey = true)]
public string Id
{
get { return (string)base["Id"]; }
set { base["Id"] = value; }
}
[ConfigurationProperty("Key")]
public string Key
{
get { return (string)base["Key"]; }
set { base["Key"] = value; }
}
[ConfigurationProperty("Email")]
public string Email
{
get { return (string)base["Email"]; }
set { base["Email"] = value; }
}
}
節點配置如下:
<configuration>
<configSections>
<section name="Alipay" type="ConsoleApplication2.AlipaySetion,ConsoleApplication2"/>
</configSections>
<Alipay Id="1234567890" Key="test1234567890" Email="[email protected]"/>
</configuration>
讀取方式:
var alipays = (AlipaySetion)ConfigurationManager.GetSection("Alipay");
string id = alipays.Id;
string key = alipays.Key;
自定義配置節點方便查看和管理,也符合面向對象開發和進行類型檢查。但我們需要寫很多ConfigurationSection類的實現。
4)使用反射技術自定義配置
.Net中使用反射技術可以動態的創建一個對象,可以調用對象的方法,可以給對象屬性賦值。我們是不是可以根據這個特點動態的創建配置類,然後給配置類的屬性賦值呢?那需要什麼呢?需要2個基礎文件,一個是對象的映射關系文件,另一個是對象屬性映射文件,如圖:
首先來看看對象的映射關系文件(文件名:System.config),內容如下:
<configuration>
<configMappings>
<mapping AssemblyName="ConsoleApplication2" ClassName="ConsoleApplication2.AlipayConfiguration"
Name="AlipayConfiguration"
section="AlipayConfiguration"
fileName="Mapping.AlipayConfiguration.config">
<field xmlName="Id" fieldName="Id" />
<field xmlName="Key" fieldName="Key" />
<field xmlName="Email" fieldName="Email" />
</mapping>
<mapping AssemblyName="ConsoleApplication2" ClassName="ConsoleApplication2.TenpayConfiguration"
Name="TenpayConfiguration"
section="TenpayConfiguration"
fileName="Mapping.TenpayConfiguration.config">
<field xmlName="Id" fieldName="Id" />
<field xmlName="Key" fieldName="Key" />
</mapping>
</configMappings>
</configuration>
對象屬性映射文件:
支付寶配置類文件(Mapping.AlipayConfiguration.config)
<?xml version="1.0" encoding="utf-8" ?>
<AlipayConfiguration>
<node name="Id" value="1234567890"/>
<node name="Key" value="test1234567890"/>
<node name="Email" value="[email protected]" />
</AlipayConfiguration>
Tenpay配置類文件(Mapping.TenpayConfiguration.config)
<?xml version="1.0" encoding="utf-8" ?>
<TenpayConfiguration>
<node name="Id" value="1234567890"/>
<node name="Key" value="test1234567890"/>
</TenpayConfiguration>
xml文件我就不做過多說明了,很簡單。看到節點名稱基本就能猜出其意思。下面來設計映射類和配置管理類,配置管理類顧名思義就能知道是管理所有配置類的。那怎樣才能管理所有的配置類呢?我們知道object是所有對象的基類。當然我們的配置類也是繼承object的。我們可以設計一個鍵值對的集合來存放所有的配置信息。比如:private Dictionary<string, object> Mappings。其中的keyi就是配置的類名,value就是配置對象。我們先看看對象的映射類的定義:
public class ConfigMapping
{
private Dictionary<string, string> fieldMappings;
/// <summary>
/// 配置名(唯一)
/// </summary>
public string Name
{
get;
set;
}
/// <summary>
/// 配置對象程序集名
/// </summary>
public string AssemblyName
{
get;
set;
}
/// <summary>
/// 配置對象類名
/// </summary>
public string ClassName
{
get;
set;
}
/// <summary>
/// 配置對象文件
/// </summary>
public string ConfigFile
{
get;
set;
}
/// <summary>
/// 類型
/// </summary>
private Type type;
/// <summary>
/// 配置對象類型
/// </summary>
public Type Type
{
get
{
return Type.GetType(ClassName + "," + AssemblyName);
}
set
{
type = value;
Instance = Activator.CreateInstance(Type.GetType(ClassName + "," + AssemblyName));
}
}
/// <summary>
/// 配置對象實例
/// </summary>
public object Instance
{
get;
private set;
}
//域集合
public Dictionary<string, string> FieldMappings
{
get
{
return fieldMappings ?? (new Dictionary<string, string>());
}
set
{
fieldMappings = value;
}
}
}
配置管理類ConfigManager代碼:
public class ConfigManager
{
private static readonly object sync = new object();
private static ConfigManager manager;
private Dictionary<string, object> Mappings;
private const string configFile = "Configuration/System.config";
private ConfigManager()
{
Mappings = new Dictionary<string, object>();
}
public static ConfigManager Instance
{
get
{
lock (sync)
{
if (manager == null)
{
lock (sync)
{
manager = new ConfigManager();
manager.Init();
}
}
}
return manager;
}
}
/// <summary>
/// 初始化配置管理
/// </summary>
privatevoid Init()
{
string path = AppDomain.CurrentDomain.BaseDirectory + configFile;
var document = new XmlDocument();
document.Load(path);
var nodes = document.SelectNodes("configuration/configMappings/mapping");
foreach (XmlNode node in nodes)
{
var mapping = new ConfigMapping
{
Name = node.Attributes["Name"].InnerText,
AssemblyName = node.Attributes["AssemblyName"].InnerText,
ClassName = node.Attributes["ClassName"].InnerText,
ConfigFile = node.Attributes["fileName"].InnerText,
Type =
Type.GetType(node.Attributes["ClassName"].InnerText + "," +
node.Attributes["AssemblyName"].InnerText)
};
foreach (XmlNode childNode in node.SelectNodes("field"))
{
mapping.FieldMappings.Add(childNode.Attributes["xmlName"].InnerText,
childNode.Attributes["fieldName"].InnerText);
}
SetProperty(mapping);
Mappings.Add(mapping.Name, mapping.Instance);
}
}
/// <summary>
/// 設置對象屬性值
/// </summary>
/// <param name="mapping"></param>
private void SetProperty(ConfigMapping mapping)
{
var xml = new XmlDocument();
xml.Load(AppDomain.CurrentDomain.BaseDirectory + "Configuration/" + mapping.ConfigFile);
var ns = xml.SelectSingleNode(mapping.Name);
var infos = mapping.Instance.GetType().GetProperties();
foreach (var info in infos)
{
foreach (XmlNode n in ns.ChildNodes)
{
if (n.Attributes["name"].Value == info.Name)
{
object value = Convert.ChangeType(n.Attributes["value"].Value, info.PropertyType);
info.SetValue(mapping.Instance, value, null);
}
}
}
}
/// <summary>
/// 獲取配置類實例
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public object GetMappingByName(string name)
{
return Mappings[name];
}
}
讀取配置信息很簡單,代碼如下:
var alipay = (AlipayConfiguration) ConfigManager.Instance.GetMappingByName("AlipayConfiguration");
long alipayId = alipay.Id;
string alipayKey = alipay.Key;
var tenpay = (TenpayConfiguration)ConfigManager.Instance.GetMappingByName("TenpayConfiguration");
long tenpayId = tenpay.Id;
string tenpayKey = tenpay.Key;
總結:這篇文章主要是介紹了AppSettingsSection類,NameValueSectionHandler類,自定義節點類,和設計一個配置管理類,來配置我們的各種信息。各有優缺點。大家在實際的項目開發中,根據網站配置信息多少,選擇適合自己的配置方式。
好了,感謝閱讀,希望這篇文章能給你帶來幫助!