在分佈式服務站點體系中,應用程序配置往往都是隨程序發佈包走,在線上運營的過程中,未有自動化部署工具的情況下,靠人力來部署上百臺應用服務器,非同一般。即便通過自動化工具來完成配置更新與部署,多少還是要煩勞運維人員。於是乎,我們可以通過配置項的單點化來實現:通過在DB端完成數據配置,各應用系統共享配置項,數據、配置更新依賴緩存及時刷新即可。
如有特殊需求,需要對單臺服務器做配置區分,則可以通過增加APP配置的優先級來調整實現本地、DB端配置的順序。 實現方式間接明瞭,下面給出示例:
1、Cache配置數據
/// <summary>
/// 獲取配置表中數據並緩存
/// </summary>
/// <returns></returns>
public static List<InitialParamEntity> GetList()
{
WebLog.WriteStart("Get Parameter List...");
List<InitialParamEntity> list = null;
try
{
string key = Consts.Keys.GET_PARA_INIT_INFO;
if (HttpContext.Current == null || HttpContext.Current.Cache[key] == null)
{
list = ParameterDA.GetList();
CacheHelper.Store(key, list);
}
list = CacheHelper.GetCache<List<InitialParamEntity>>(key);
}
catch (System.Exception ex)
{
WebLog.WriteStart("Get Parameter Exception:" + ex.GetObjectDetails("|"));
}
return list;
}
/// <summary>
/// Summary description for InitialParamEntity
/// </summary>
public class InitialParamEntity
{
/// <summary>
/// 參數類型
/// </summary>
public string ParaType
{
get;
set;
}
/// <summary>
/// 參數名
/// </summary>
public string ParaKey
{
get;
set;
}
/// <summary>
/// 參數值
/// </summary>
public string ParaValue
{
get;
set;
}
}
2、緩存刷新(略)
在HttpHandler中配置緩存刷新Path,通過該Path以及對應的刷新參數,完成對應緩存或全緩存的刷新
3、配置項處理
建立配置類,繼承IConfigurationSectionHandler, 在Global入口處調用Init方法完成數據初始化
public class MyConfig : IConfigurationSectionHandler
{
private MyConfig() { }
#region read appsettings
#region 不同參數類型
#region 默認配置
public static string GetConfig(string key)
{
string config = GetConfig<string>(key);
if (String.IsNullOrEmpty(config))
{
return string.Empty;
}
return config;
}
public static T GetConfig<T>(string key)
{
return GetConfig<T>(key, default(T));
}
public static T GetConfig<T>(string key,T defaultValue)
{
if (Params == null || Params.Count == 0)
return defaultValue;
string parValue = Params.Get(key);
if (!String.IsNullOrEmpty(parValue))
{
return (T)Convert.ChangeType(parValue, typeof(T));
}
return defaultValue;
}
#endregion
#region Url 跳轉
/// <summary>
/// 用戶獲取根據類型獲得URL跳轉地址
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public static T GetMap<T>(string key)
{
if (MapPath == null || MapPath.Count == 0)
return default(T);
string parValue = MapPath.Get(key);
if (!String.IsNullOrEmpty(parValue))
{
return (T)Convert.ChangeType(parValue, typeof(T));
}
return default(T);
}
public static string GetMap(string key)
{
return GetMap<string>(key);
}
#endregion
#endregion
public static string GetRadomConfig(string key, string defaultValue)
{
return GetRadomConfig<string>(key, defaultValue);
}
public static T GetRadomConfig<T>(string key, T defaultValue)
{
string result = GetConfig(key);
string[] tempRet = result.Split(';');
Random random = new Random();
int index = random.Next(0, tempRet.Length);
result = tempRet[index];
return (T)Convert.ChangeType(result, typeof(T));
}
/// <summary>
/// 隨機取一個值
/// </summary>
/// <returns></returns>
private static string GetRadomConfig(string value)
{
string[] serverList = value.Split(',');
if (serverList.Length == 0) throw new ArgumentException("請求參數異常");
int len = serverList.Length;
if (len > 1)
{
Random rd = new Random((int)(DateTime.Now.Ticks));
int rdNum = rd.Next(len);
return serverList[rdNum];
}
return serverList[0];
}
#endregion
#region Public attribute
private static NameValueCollection _mapPath;
public static NameValueCollection MapPath
{
get { return _mapPath; }
}
private static NameValueCollection _params;
public static NameValueCollection Params
{
get { return _params; }
}
[Config(Key = "PayOrdersConnectionString", DefaultValue = "")]
private static string payOrdersConnectionString;
/// <summary>
/// 新的訂單庫
/// </summary>
public static string PayOrdersConnectionString
{
get
{
return payOrdersConnectionString;
}
}
#endregion
#region internal
static void SetField(Action<FieldInfo, ConfigAttribute> action)
{
Type type = typeof(MerchantConfig);
FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
foreach (FieldInfo field in fields)
{
ConfigAttribute configAttr = (ConfigAttribute)Attribute.GetCustomAttribute(field, typeof(ConfigAttribute));
if (configAttr != null)
{
action(field, configAttr);
}
}
}
static void SetParamsValue(FieldInfo field, ConfigAttribute configAttr)
{
foreach (string s in Params.AllKeys)
{
if (string.Compare(s, configAttr.Key, true) == 0)
{
field.SetValue(null, Convert.ChangeType(Params[configAttr.Key], configAttr.ValueType));
}
}
}
static void SetFieldDefault(FieldInfo field, ConfigAttribute configAttr)
{
field.SetValue(null, Convert.ChangeType(configAttr.DefaultValue, configAttr.ValueType));
}
internal static void UserDefinedCreate(NameValueCollection settings, NameValueCollection mapPath)
{
if (settings != null)
{
//Config配置,優先級高於數據庫配置
NameValueCollection rewriterSettings = (NameValueCollection)System.Configuration.ConfigurationManager.GetSection("MyParamSettings");
if (rewriterSettings != null)
{
foreach (string key in rewriterSettings.Keys)
{
//!string.IsNullOrEmpty(rewriterSettings[key]), 允許空字符
if (rewriterSettings[key] != null)
{
if (settings[key] != null)
{
WebLog.WriteStart("數據庫:" + key + ":" + settings[key]);
WebLog.WriteStart("Config:" + key + ":" + rewriterSettings[key]);
settings[key] = rewriterSettings[key];
}
else if (mapPath[key] != null)
{
WebLog.WriteStart("數據庫:" + key + ":" + mapPath[key]);
WebLog.WriteStart("Config:" + key + ":" + rewriterSettings[key]);
mapPath[key] = rewriterSettings[key];
}
}
}
}
_mapPath = mapPath;
_params = settings;
SetField(SetParamsValue);
}
else
{
SetField(SetFieldDefault);
}
}
/// <summary>
/// 獲取數據庫配置數據:初始化Config,生成靜態XML配置文件
/// </summary>
public static void Init(List<InitialParamEntity> list)
{
NameValueCollection mapPath = new NameValueCollection();
NameValueCollection setting = new NameValueCollection();
foreach (InitialParamEntity param in list)
{
if (param.ParaType != null && param.ParaType.ToUpper() == "MAPPATH")
{
mapPath.Add(param.ParaKey, param.ParaValue);
}
else
{
setting.Add(param.ParaKey, param.ParaValue);
}
WebLog.WriteStart(param.ParaKey + ", " + param.ParaValue);
}
UserDefinedCreate(setting, mapPath);
}
#endregion
#region IConfigurationSectionHandler 成員
public object Create(object parent, object configContext, System.Xml.XmlNode section)
{
//調用自定義的初始化函數
System.Diagnostics.Debug.WriteLine("config is modified------");
NameValueCollection settings;
try
{
System.Diagnostics.Debug.WriteLine("-------- Begin read configuration file");
NameValueSectionHandler baseHandler = new NameValueSectionHandler();
settings = (NameValueCollection)baseHandler.Create(parent, configContext, section);
}
catch
{
settings = null;
}
return settings;
}
#endregion
}
#region 默認值屬性類
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
internal class ConfigAttribute : Attribute
{
private object defaultValue;
private string key;
private Type valueType = typeof(string);
public object DefaultValue
{
get { return defaultValue; }
set { defaultValue = value; }
}
public string Key
{
get { return key; }
set { key = value; }
}
public Type ValueType
{
get { return valueType; }
set { valueType = value; }
}
}
#endregion
4、提升單臺機器配置優先級
<section name="MyParamSettings" type="System.Configuration.NameValueSectionHandler,System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<MyParamSettings>
<!-- 優先級高於數據庫配置項 -->
<add key="IFunctionService" value="http://www.baiduc.om" />
</MyParamSettings>
5、配置項應用
MyConfig.GetConfig("IFunctionService")
MyConfig.GetConfig<string>("IFunctionService")
MyConfig.GetConfig<int>("IFunctionService")