上篇 : http://www.BkJia.com/kf/201110/109223.html
說了對配置文件的修改,基本上都已經是全部了,後來也補充了SingleTagSectionHandler的訪問,現在把對SingleTagSectionHandler的寫以及一些能偷懶的方法一起說下,希望大家有好東西都能夠分享下,有時用到了,就是好東西,不用到就當作是學習吧
提供二個訪問配置文件的靜態方法
/// <summary>
/// 打開默認的配置文件.exe.config
/// </summary>
/// <returns></returns>
public static Configuration GetConfiguration()
{
return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
}
/// <summary>
/// 獲取指定的配置文件。
/// </summary>
/// <param name="configFullPath">配置文件的全名稱</param>
/// <returns></returns>
public static Configuration GetConfiguration(string configFullPath)
{
ExeConfigurationFileMap configFile = new ExeConfigurationFileMap();
configFile.ExeConfigFilename = configFullPath;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
return config;
}
通過上兩個靜態方法可以獲取到Configuration實例
獲取SingleTagSectionHandler節點的值的多個方法
/// <summary>
/// 獲取SingleTagSectionHandler某節點的值。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <param name="property"></param>
/// <returns></returns>
public static string GetSingleTagSectionItemValue(this Configuration config, string sectionName, string property)
{
Dictionary<string, string> dict = GetSingleTagSectionValues(config, sectionName);
if (dict != null && dict.Count > 0)
{
if (dict.ContainsKey(property))
return (string)dict[property];
}
return null;
}
/// <summary>
/// 獲取SingleTagSectionHandler節點的值。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <returns></returns>
public static Dictionary<string, string> GetSingleTagSectionValues(this Configuration config, string sectionName)
{
var section = config.GetSection(sectionName);
if (section == null || section.SectionInformation == null)
return null;
ConfigXmlDocument xdoc = new ConfigXmlDocument();
xdoc.LoadXml(section.SectionInformation.GetRawXml());
System.Xml.XmlNode xnode = xdoc.ChildNodes[0];
Dictionary<string, string> result = new Dictionary<string, string>();
IDictionary dict = (IDictionary)(new SingleTagSectionHandler().Create(null, null, xnode));
foreach (string str in dict.Keys)
{
result[str] = (string)dict[str];
}
return result;
}
更新SingleTagSection只能通過Xml來實現,在些使用了ConfigXmlDocument類,通過更改DefaultSection的SectionInfomation的RawXml來完成,同時更改SectionInformation.Type為SingleTagSectionHandler的完全限定名。
更新和刪除
/// <summary>
/// 更新配置節,相同的就修改,沒有的就增加。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <param name="items"></param>
public static void UpdateSingleTagSectionValues(this Configuration config, string sectionName, Dictionary<string, string> items)
{
Dictionary<string, string> orgItem = GetSingleTagSectionValues(config, sectionName);
if (orgItem == null)
orgItem = new Dictionary<string, string>();
foreach (string key in items.Keys)
{
orgItem[key] = items[key];
}
UpdateSingleTagSection(config, sectionName, orgItem);
}
/// <summary>
/// 刪除配置點的一些配置。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <param name="items"></param>
public static void RemoveSingleTagSectionValues(this Configuration config, string sectionName, Dictionary<string, string> items)
{
Dictionary<string, string> orgItem = GetSingleTagSectionValues(config, sectionName);
if (orgItem != null)
{
foreach (string key in items.Keys)
{
orgItem.Remove(key);
}
UpdateSingleTagSection(config, sectionName, orgItem);
}
}
private static void UpdateSingleTagSection(Configuration config, string sectionName, Dictionary<string, string> items)
{
config.Sections.Remove(sectionName);
DefaultSection section = new DefaultSection();
config.Sections.Add(sectionName, section);
ConfigXmlDocument xdoc = new ConfigXmlDocument();
XmlNode secNode = xdoc.CreateNode(XmlNodeType.Element, sectionName, xdoc.NamespaceURI);
xdoc.AppendChild(secNode);
foreach (string key in items.Keys)
{
XmlAttribute attr = xdoc.CreateAttribute(key);
attr.Value = items[key];
secNode.Attributes.Append(attr);
}
section.SectionInformation.SetRawXml(xdoc.OuterXml);
section.SectionInformation.Type = typeof(SingleTagSectionHandler).AssemblyQualifiedName;
config.Save(ConfigurationSaveMode.Modified);
}
應該還得提供一個對自定義的配置節訪問和讀寫的方法,以更好的擴充
自定義配置節
/// <summary>
/// 獲取自定義的配置節。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <returns></returns>
public static T GetCustomSection<T>(this Configuration config, string sectionName) where T : ConfigurationSection
{
return (T)config.GetSection(sectionName);
}
/// <summary>
/// 保存自定義配置節。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="config"></param>
/// <param name="section"></param>
/// <param name="sectionName"></param>
public static void SaveCustomSection<T>(this Configuration config, T section, string sectionName) where T : ConfigurationSection
{
config.RemoveSection(sectionName);
config.Sections.Add(sectionName, section);
config.Save(ConfigurationSaveMode.Modified);
}
至於配置組,本人覺得用處不大,實現起來也很別扭,所在就不實現了,如果真的是很復雜的配置,建議自己定義一個配置節吧。
下面一些懶人的方法,本人覺得還是很不錯的,至少會省掉不少的開發時間。
通過反射對實體或靜態屬性進行賦值,在此假設obj如果為null就使用靜態屬性。
反射獲取屬性值
private static void SetPropertiesValue(object obj, Dictionary<string, string> items, Type cfgEtyType)
{
BindingFlags bf = BindingFlags.Public;
if (obj == null)
bf |= BindingFlags.Static;
else
bf |= BindingFlags.Instance;
PropertyInfo[] pinfos = cfgEtyType.GetProperties(bf);
foreach (PropertyInfo p in pinfos)
{
try
{
if (items.ContainsKey(p.Name))
{
string val = items[p.Name];
if (!string.IsNullOrEmpty(val))
{
if (p.PropertyType.IsEnum)
{
//判斷是否為數字
if (isDigital(val))
{
p.SetValue(obj, Enum.Parse(p.PropertyType, val, true), null);
}
else
{
//判斷是否存在該名稱
if (isExistEnumKey(p.PropertyType, val))
p.SetValue(obj, Enum.Parse(p.PropertyType, val, true), null);
}
}
else if (p.PropertyType.IsValueType) //值類型
{
MethodInfo minfo = p.PropertyType.GetMethod("Parse", new Type[] { typeof(string) });
if (minfo != null)
{
p.SetValue(obj, minfo.Invoke(null, new object[] { val }), null);
}
}
else
p.SetValue(obj, val, null);
}
else if (!p.PropertyType.IsEnum && !p.PropertyType.IsValueType)
p.SetValue(obj, val, null);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
}
}
}
/// <summary>
/// 判斷枚舉值是否為數字
/// </summary>
/// <param name="strValue"></param>
/// <returns></returns>
private static bool isDigital(string strValue)
{
return Regex.IsMatch(strValue, @"^(\d+)$");
}
/// <summary>
/// 判斷是否存在枚舉的名稱
/// </summary>
/// <param name="type"></param>
/// <param name="keyName"></param>
/// <returns></returns>
private static bool isExistEnumKey(Type type, string keyName)
{
bool isExist = false;
foreach (string key in Enum.GetNames(type))
{
if (key.Equals(keyName, StringComparison.OrdinalIgnoreCase))
{
isExist = true;
break;
}
}
return isExist;
}
動態獲取值,在此再次強調,屬性值必需和配置節的Key等相同,包括大小寫。
使用抽象類的靜態屬性來取出配置節的值
/// <summary>
/// 使用反射獲取實體配置節的值,實體的靜態屬性必需和配置的Key相同。
/// </summary>
/// <param name="config">打開的配置實例</param>
/// <typeparam name="T">要取值的類,類的靜態屬性要和Key值對應</typeparam>
/// <param name="sectionName">T 對就的配置節的名稱</param>
public static void GetKeyValueSectionConfigValue<T>(this Configuration config, string sectionName) where T : class
{
try
{
Dictionary<string, string> dict = GetKeyValueSectionValues(config, sectionName);
Type cfgEtyType = typeof(T);
SetPropertiesValue(null, dict, cfgEtyType);
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
}
}
提供幾個和Configuration實例無關的輔助方法,但也作為擴展方法來實現,以方便操作,只要由實例和抽象類來獲取到HashTable的值,和反過來取得實例的值
輔助方法
/// <summary>
/// 由集合根據字段的屬性生成實體。屬性名為key,屬性值為value。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="config"></param>
/// <param name="items"></param>
/// <returns></returns>
public static T GetConfigEntityByItems<T>(this Configuration config, Dictionary<string, string> items) where T : class
{
Type etyType = typeof(T);
Func<object> func = etyType.CreateInstanceDelegate();
object ety = func.Invoke();
SetPropertiesValue(ety, items, etyType);
return (T)ety;
}
/// <summary>
/// 由實例生成配置的項。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="config">沒有實際使用到</param>
/// <param name="instance"></param>
/// <returns></returns>
public static Dictionary<string, string> GetItemsByConfigEntity<T>(this Configuration config, T instance) where T : class
{
Type cfgEtyType = typeof(T);
BindingFlags bf = BindingFlags.Public;
if (instance == null)
bf |= BindingFlags.Static;
else
bf |= BindingFlags.Instance;
PropertyInfo[] pinfos = cfgEtyType.GetProperties(bf);
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (PropertyInfo p in pinfos)
{
dict[p.Name] = "" + p.GetValue(instance, null);
}
return dict;
}
/// <summary>
/// 由類的靜態屬性生成配置項。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Dictionary<string, string> GetItemsByClass<T>(this Configuration config) where T : class
{
return GetItemsByConfigEntity<T>(config, null);
}
從appSettings獲取值
/// <summary>
/// 獲取appSettings的配置值。Key值 和 T 的靜態屬性相同才能取出來。
/// </summary>
/// <param name="config">打開的配置實例</param>
/// <typeparam name="T">要取值的類,類的靜態屬性要和Key值對應</typeparam>
public static void GetAppSettingsConfigValue<T>(this Configuration config) where T : class
{
//通過反射自動值,增加屬性只需把配置的key值和屬性的名稱相同即可。
////Type cfgType = typeof(ConfigUtility);
////MethodInfo getAppConfigMethod = cfgType.GetMethod("GetAppConfig", BindingFlags.Static | BindingFlags.Public);
Type etyType = typeof(T);
Dictionary<string, string> items = GetAppSettings(config);
SetPropertiesValue(null, items, etyType);
}
配置節的保存
保存配置節
/// <summary>
/// 保存 Section 配置的值。保存為DictionarySectionHandler配置節。
/// </summary>
/// <param name="config"></param>
/// <typeparam name="T"></typeparam>
/// <param name="sectionName"></param>
public static void SaveKeyValueSectionConfig<T>(this Configuration config, string sectionName) where T : class
{
var orgsection = config.GetSection(sectionName);
if (orgsection != null)
config.Sections.Remove(sectionName);
AppSettingsSection section = new AppSettingsSection();
config.Sections.Add(sectionName, section);
Type etyType = typeof(T);
foreach (PropertyInfo pinfo in etyType.GetProperties(BindingFlags.Static | BindingFlags.Public))
{
string keyName = pinfo.Name;
object objValue = pinfo.GetValue(null, null);
////section.Settings.Remove(keyName);
section.Settings.Add(new KeyValueConfigurationElement(keyName, "" + objValue));
}
section.SectionInformation.Type = typeof(DictionarySectionHandler).AssemblyQualifiedName;
config.Save(ConfigurationSaveMode.Modified);
}
/// <summary>
/// 保存為 AppSettings 配置的值。
/// </summary>
/// <typeparam name="T"></typeparam>
public static void SaveAppSettingsConfig<T>(this Configuration config) where T : class
{
try
{
Type etyType = typeof(T);
foreach (PropertyInfo pinfo in etyType.GetProperties(BindingFlags.Static | BindingFlags.Public))
{
string keyName = pinfo.Name;
object objValue = pinfo.GetValue(null, null);
UpdateAppSettingsItemNoSave(config, keyName, "" + objValue);
}
config.Save(ConfigurationSaveMode.Modified);
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
}
}
配置文件修改系列在此告一段落了,再附加上創建實體用到的Type的擴展,是從網絡抄摘下來的,在本息用了代替Activator來創建實例,效率會快點。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace System
{
public static class TypeExtensions
{
public static Func<object> CreateInstanceDelegate(this Type type)
{
NewExpression newExp = Expression.New(type);
Expression<Func<object>> lambdaExp =
Expression.Lambda<Func<object>>(newExp, null);
Func<object> func = lambdaExp.Compile();
return func;
}
public static Func<T, object> CreateInstanceDelegate<T>(this Type type)
{
Type paramType = typeof(T);
var construtor = type.GetConstructor(new Type[] { paramType });
var param = new ParameterExpression[] { Expression.Parameter(paramType, "arg") };
NewExpression newExp = Expression.New(construtor, param);
Expression<Func<T, object>> lambdaExp =
Expression.Lambda<Func<T, object>>(newExp, param);
Func<T, object> func = lambdaExp.Compile();
return func;
}
public static Func<T1, T2, object> CreateInstanceDelegate<T1, T2>(this Type type)
{
var types = new Type[] { typeof(T1), typeof(T2) };
var construtor = type.GetConstructor(types);
int i = 0;
var param = types.Select(t => Expression.Parameter(t, "arg" + (i++))).ToArray();
NewExpression newExp = Expression.New(construtor, param);
Expression<Func<T1, T2, object>> lambdaExp = Expression.Lambda<Func<T1, T2, object>>(newExp, param);
Func<T1, T2, object> func = lambdaExp.Compile();
return func;
}
//以下方法中的Lambda表達式“Expression<Func<object[], object>> ”已經定義參數是object[], 而構造函數的參數卻不能自動轉化。當使用以下代碼作測試,
//////以下代碼有bug!
////public static Func<object[], object> CreateInstanceDelegate(this Type type, params object[] args)
////{
//// var construtor = type.GetConstructor(args.Select(c => c.GetType()).ToArray());
//// var param = buildParameters(args);
//// NewExpression newExp = Expression.New(construtor, param);
//// Expression<Func<object[], object>> lambdaExp =
//// Expression.Lambda<Func<object[], object>>(newExp, param);
//// Func<object[], object> func = lambdaExp.Compile();
//// return func;
////}
////static ParameterExpression[] buildParameters(object[] args)
////{
//// int i = 0;
//// List<ParameterExpression> list = new List<ParameterExpression>();
//// foreach (object arg in args)
//// {
//// list.Add(Expression.Parameter(arg.GetType(), "arg" + (i++)));
//// }
//// return list.ToArray();
////}
}
}
-----------------The End----------------
謝謝大家!
本文出自 Lance Yang