上篇
说了对配置文件的修改,基本上都已经是全部了,后来也补充了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来创建实例,效率会快点。
View Code 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----------------
谢谢大家!
本文出自: