ConfigurationExtension.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.Specialized;
  4. using System.Configuration;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Text;
  8. using System.Xml;
  9. using System.IO;
  10. namespace SuperSocket.Common
  11. {
  12. /// <summary>
  13. /// Configuration extension class
  14. /// </summary>
  15. public static class ConfigurationExtension
  16. {
  17. /// <summary>
  18. /// Gets the value from namevalue collection by key.
  19. /// </summary>
  20. /// <param name="collection">The collection.</param>
  21. /// <param name="key">The key.</param>
  22. /// <returns></returns>
  23. public static string GetValue(this NameValueCollection collection, string key)
  24. {
  25. return GetValue(collection, key, string.Empty);
  26. }
  27. /// <summary>
  28. /// Gets the value from namevalue collection by key.
  29. /// </summary>
  30. /// <param name="collection">The collection.</param>
  31. /// <param name="key">The key.</param>
  32. /// <param name="defaultValue">The default value.</param>
  33. /// <returns></returns>
  34. public static string GetValue(this NameValueCollection collection, string key, string defaultValue)
  35. {
  36. if (string.IsNullOrEmpty(key))
  37. throw new ArgumentNullException("key");
  38. if (collection == null)
  39. return defaultValue;
  40. var e = collection[key];
  41. if (e == null)
  42. return defaultValue;
  43. return e;
  44. }
  45. /// <summary>
  46. /// Deserializes the specified configuration section.
  47. /// </summary>
  48. /// <typeparam name="TElement">The type of the element.</typeparam>
  49. /// <param name="section">The section.</param>
  50. /// <param name="reader">The reader.</param>
  51. public static void Deserialize<TElement>(this TElement section, XmlReader reader)
  52. where TElement : ConfigurationElement
  53. {
  54. if (section is ConfigurationElementCollection)
  55. {
  56. var collectionType = section.GetType();
  57. var att = collectionType.GetCustomAttributes(typeof(ConfigurationCollectionAttribute), true).FirstOrDefault() as ConfigurationCollectionAttribute;
  58. if (att != null)
  59. {
  60. var property = collectionType.GetProperty("AddElementName", BindingFlags.NonPublic | BindingFlags.Instance);
  61. property.SetValue(section, att.AddItemName, null);
  62. property = collectionType.GetProperty("RemoveElementName", BindingFlags.NonPublic | BindingFlags.Instance);
  63. property.SetValue(section, att.RemoveItemName, null);
  64. property = collectionType.GetProperty("ClearElementName", BindingFlags.NonPublic | BindingFlags.Instance);
  65. property.SetValue(section, att.ClearItemsName, null);
  66. }
  67. }
  68. var deserializeElementMethod = typeof(TElement).GetMethod("DeserializeElement", BindingFlags.NonPublic | BindingFlags.Instance);
  69. deserializeElementMethod.Invoke(section, new object[] { reader, false });
  70. }
  71. /// <summary>
  72. /// Deserializes the child configuration.
  73. /// </summary>
  74. /// <typeparam name="TConfig">The type of the configuration.</typeparam>
  75. /// <param name="childConfig">The child configuration string.</param>
  76. /// <returns></returns>
  77. public static TConfig DeserializeChildConfig<TConfig>(string childConfig)
  78. where TConfig : ConfigurationElement, new()
  79. {
  80. // removed extra namespace prefix
  81. childConfig = childConfig.Replace("xmlns=\"http://schema.supersocket.net/supersocket\"", string.Empty);
  82. XmlReader reader = new XmlTextReader(new StringReader(childConfig));
  83. var config = new TConfig();
  84. reader.Read();
  85. config.Deserialize(reader);
  86. return config;
  87. }
  88. /// <summary>
  89. /// Gets the child config.
  90. /// </summary>
  91. /// <typeparam name="TConfig">The type of the config.</typeparam>
  92. /// <param name="childElements">The child elements.</param>
  93. /// <param name="childConfigName">Name of the child config.</param>
  94. /// <returns></returns>
  95. public static TConfig GetChildConfig<TConfig>(this NameValueCollection childElements, string childConfigName)
  96. where TConfig : ConfigurationElement, new()
  97. {
  98. var childConfig = childElements.GetValue(childConfigName, string.Empty);
  99. if (string.IsNullOrEmpty(childConfig))
  100. return default(TConfig);
  101. return DeserializeChildConfig<TConfig>(childConfig);
  102. }
  103. /// <summary>
  104. /// Gets the config source path.
  105. /// </summary>
  106. /// <param name="config">The config.</param>
  107. /// <returns></returns>
  108. public static string GetConfigSource(this ConfigurationElement config)
  109. {
  110. var source = config.ElementInformation.Source;
  111. if (!string.IsNullOrEmpty(source) || !Platform.IsMono)
  112. return source;
  113. var configProperty = typeof(ConfigurationElement).GetProperty("Configuration", BindingFlags.Instance | BindingFlags.NonPublic);
  114. if (configProperty == null)
  115. return string.Empty;
  116. var configuration = (Configuration)configProperty.GetValue(config, null);
  117. return configuration.FilePath;
  118. }
  119. /// <summary>
  120. /// Loads configuration element's node information from a model.
  121. /// </summary>
  122. /// <param name="configElement">The config element.</param>
  123. /// <param name="source">The source.</param>
  124. /// <exception cref="System.Exception">Cannot find expected property 'Item' from the type 'ConfigurationElement'.</exception>
  125. public static void LoadFrom(this ConfigurationElement configElement, object source)
  126. {
  127. // get index property setter
  128. var indexPropertySetter = configElement.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetProperty)
  129. .FirstOrDefault(p =>
  130. {
  131. if (!p.Name.Equals("Item"))
  132. return false;
  133. var parameters = p.GetIndexParameters();
  134. if (parameters == null || parameters.Length != 1)
  135. return false;
  136. return parameters[0].ParameterType == typeof(string);
  137. });
  138. if (indexPropertySetter == null)
  139. throw new Exception("Cannot find expected property 'Item' from the type 'ConfigurationElement'.");
  140. // source properties
  141. var properties = source.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);
  142. var targetProperties = configElement.GetType()
  143. .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty)
  144. .ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);
  145. var emptyObjectArr = new object[0];
  146. var writableAttrs = new List<KeyValuePair<PropertyInfo, PropertyInfo>>();
  147. foreach (var sourceProperty in properties)
  148. {
  149. if (!sourceProperty.PropertyType.IsSerializable)
  150. continue;
  151. PropertyInfo targetProperty;
  152. if (targetProperties.TryGetValue(sourceProperty.Name, out targetProperty))
  153. {
  154. if (targetProperty.CanWrite)
  155. {
  156. writableAttrs.Add(new KeyValuePair<PropertyInfo, PropertyInfo>(sourceProperty, targetProperty));
  157. continue;
  158. }
  159. }
  160. var value = sourceProperty.GetValue(source, emptyObjectArr);
  161. // lower the first char
  162. var nameChars = sourceProperty.Name.ToArray();
  163. nameChars[0] = char.ToLower(nameChars[0]);
  164. var propertyName = new string(nameChars);
  165. indexPropertySetter.SetValue(configElement, value, new object[] { propertyName });
  166. }
  167. foreach (var pair in writableAttrs)
  168. {
  169. var value = pair.Key.GetValue(source, emptyObjectArr);
  170. pair.Value.SetValue(configElement, value, emptyObjectArr);
  171. }
  172. }
  173. /// <summary>
  174. /// Gets the current configuration of the configuration element.
  175. /// </summary>
  176. /// <returns>The current configuration.</returns>
  177. /// <param name="configElement">Configuration element.</param>
  178. public static Configuration GetCurrentConfiguration(this ConfigurationElement configElement)
  179. {
  180. var configElementType = typeof(ConfigurationElement);
  181. var configProperty = configElementType.GetProperty("CurrentConfiguration", BindingFlags.Instance | BindingFlags.Public);
  182. if(configProperty == null)
  183. configProperty = configElementType.GetProperty("Configuration", BindingFlags.Instance | BindingFlags.NonPublic);
  184. if (configProperty == null)
  185. return null;
  186. return (Configuration)configProperty.GetValue(configElement, null);
  187. }
  188. private static void ResetConfigurationForMono(AppDomain appDomain, string configFilePath)
  189. {
  190. appDomain.SetupInformation.ConfigurationFile = configFilePath;
  191. var configSystem = typeof(ConfigurationManager)
  192. .GetField("configSystem", BindingFlags.Static | BindingFlags.NonPublic)
  193. .GetValue(null);
  194. // clear previous state
  195. typeof(ConfigurationManager)
  196. .Assembly.GetTypes()
  197. .Where(x => x.FullName == "System.Configuration.ClientConfigurationSystem")
  198. .First()
  199. .GetField("cfg", BindingFlags.Instance | BindingFlags.NonPublic)
  200. .SetValue(configSystem, null);
  201. }
  202. private static void ResetConfigurationForDotNet(AppDomain appDomain, string configFilePath)
  203. {
  204. appDomain.SetData("APP_CONFIG_FILE", configFilePath);
  205. // clear previous state
  206. BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Static;
  207. typeof(ConfigurationManager)
  208. .GetField("s_initState", flags)
  209. .SetValue(null, 0);
  210. typeof(ConfigurationManager)
  211. .GetField("s_configSystem", flags)
  212. .SetValue(null, null);
  213. typeof(ConfigurationManager)
  214. .Assembly.GetTypes()
  215. .Where(x => x.FullName == "System.Configuration.ClientConfigPaths")
  216. .First()
  217. .GetField("s_current", flags)
  218. .SetValue(null, null);
  219. }
  220. /// <summary>
  221. /// Reset application's configuration to a another config file
  222. /// </summary>
  223. /// <param name="appDomain">the assosiated AppDomain</param>
  224. /// <param name="configFilePath">the config file path want to reset to</param>
  225. public static void ResetConfiguration(this AppDomain appDomain, string configFilePath)
  226. {
  227. if (Platform.IsMono)
  228. ResetConfigurationForMono(appDomain, configFilePath);
  229. else
  230. ResetConfigurationForDotNet(appDomain, configFilePath);
  231. }
  232. }
  233. }