PageRenderTime 321ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/src/DevFx/Configuration/ConfigHelper.cs

https://github.com/mer2/DevFx
C# | 271 lines | 169 code | 25 blank | 77 comment | 51 complexity | 33ead5d53c144cc3d2c5b25a08bb7f5c MD5 | raw file
  1. /* Copyright(c) 2005-2011 R2@DevFx.NET, License(LGPL) */
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Xml;
  8. using DevFx.Configuration.Xml;
  9. using DevFx.Utils;
  10. namespace DevFx.Configuration
  11. {
  12. /// <summary>
  13. /// 关于配置的一些实用方法
  14. /// </summary>
  15. public static class ConfigHelper
  16. {
  17. public const string RootSettingName = "devfx";
  18. /// <summary>
  19. /// 缺省的XML配置文件查找目录列表
  20. /// </summary>
  21. public static readonly string[] ConfigFileDefaultSearchPath = {
  22. "./", AppDomain.CurrentDomain.BaseDirectory
  23. };
  24. /// <summary>
  25. /// 验证配置文件路径并返回
  26. /// </summary>
  27. /// <param name="fileName">配置文件名</param>
  28. /// <param name="searchPath">搜索目录列表</param>
  29. /// <returns>返回配置文件路径</returns>
  30. public static string SearchConfigFile(string fileName, string[] searchPath) {
  31. if(searchPath == null || searchPath.Length <= 0) {
  32. searchPath = ConfigFileDefaultSearchPath;
  33. }
  34. return FileHelper.SearchFile(fileName, searchPath);
  35. }
  36. /// <summary>
  37. /// 查找由通配符指定的文件集合
  38. /// </summary>
  39. /// <param name="filePattern">文件通配符</param>
  40. /// <param name="searchPath">搜索目录列表</param>
  41. /// <returns>找到的文件列表</returns>
  42. public static string[] SearchConfigFileWithPattern(string filePattern, string[] searchPath) {
  43. if(searchPath == null || searchPath.Length <= 0) {
  44. searchPath = ConfigFileDefaultSearchPath;
  45. }
  46. return FileHelper.SearchFileWithPattern(filePattern, searchPath);
  47. }
  48. /// <summary>
  49. /// 从Xml字符串中生成 <see cref="IConfigSetting"/>
  50. /// </summary>
  51. /// <param name="xmlString">Xml字符串</param>
  52. /// <returns><see cref="IConfigSetting"/></returns>
  53. public static IConfigSetting CreateFromXmlString(string xmlString) {
  54. var xmlNode = LoadXmlNodeFromString(xmlString, "/");
  55. if(xmlNode is XmlDocument) {
  56. xmlNode = ((XmlDocument)xmlNode).DocumentElement;
  57. }
  58. return XmlConfigSetting.Create(null, xmlNode, true, null, null);
  59. }
  60. /// <summary>
  61. /// 从Xml文件中生成 <see cref="IConfigSetting"/>
  62. /// </summary>
  63. /// <param name="xmlFileName">Xml文件</param>
  64. /// <returns><see cref="IConfigSetting"/></returns>
  65. public static IConfigSetting CreateFromXmlFile(string xmlFileName) {
  66. return XmlConfigSetting.Create(xmlFileName);
  67. }
  68. /// <summary>
  69. /// 从 <see cref="XmlNode"/> 生成 <see cref="IConfigSetting"/>
  70. /// </summary>
  71. /// <param name="xmlNode"><see cref="XmlNode"/></param>
  72. /// <returns><see cref="IConfigSetting"/></returns>
  73. public static IConfigSetting CreateFromXmlNode(XmlNode xmlNode) {
  74. return XmlConfigSetting.Create(null, xmlNode, true, null, null);
  75. }
  76. /// <summary>
  77. /// 从资源(Uri)中生成 <see cref="IConfigSetting"/>
  78. /// </summary>
  79. /// <param name="xmlSource">Uri字符串</param>
  80. /// <param name="sourceInType">如果是内嵌资源则表示其所在的程序集</param>
  81. /// <returns><see cref="IConfigSetting"/></returns>
  82. public static IConfigSetting CreateFromXmlSource(string xmlSource, Type sourceInType) {
  83. return CreateFromXmlSource(xmlSource, sourceInType.Assembly);
  84. }
  85. /// <summary>
  86. /// 从资源(Uri)中生成 <see cref="IConfigSetting"/>
  87. /// </summary>
  88. /// <param name="sourceName">资源的全名称</param>
  89. /// <param name="sourceAssembly">如果是内嵌资源则表示其所在的程序集</param>
  90. /// <returns><see cref="IConfigSetting"/></returns>
  91. public static IConfigSetting CreateFromXmlSource(string sourceName, Assembly sourceAssembly) {
  92. IConfigSetting setting;
  93. if (sourceName.StartsWith("res://", true, null)) {
  94. sourceName = FileHelper.GetResourceName(sourceName, out _);
  95. var stream = sourceAssembly.GetManifestResourceStream(sourceName);
  96. if (stream == null) {
  97. throw new ConfigException("未找到资源" + sourceName);
  98. }
  99. var sr = new StreamReader(stream);
  100. var xmlString = sr.ReadToEnd();
  101. setting = CreateFromXmlString(xmlString);
  102. } else if (sourceName.StartsWith("http://", true, null)) {
  103. throw new ConfigException("未实现http://");
  104. } else {
  105. setting = CreateFromXmlFile(sourceName);
  106. }
  107. return setting;
  108. }
  109. /// <summary>
  110. /// 从资源(Uri)中生成 <see cref="IConfigSetting"/>
  111. /// </summary>
  112. /// <param name="xmlSource">Uri字符串(如果是内嵌资源,则此Uri还应包含所在程序集的名称,形如:res://内嵌资源全名称, 所在程序集名称)</param>
  113. /// <returns><see cref="IConfigSetting"/></returns>
  114. public static IConfigSetting CreateFromXmlSource(string xmlSource) {
  115. var stream = FileHelper.GetFileStream(xmlSource);
  116. if (stream == null) {
  117. throw new ConfigException("未找到资源" + xmlSource);
  118. }
  119. var sr = new StreamReader(stream);
  120. var xmlString = sr.ReadToEnd();
  121. return CreateFromXmlString(xmlString);
  122. }
  123. /// <summary>
  124. /// 创建无内容的配置节
  125. /// </summary>
  126. /// <returns>配置节</returns>
  127. public static IConfigSetting CreateEmptySetting() {
  128. return CreateFromXmlString("<configuration />");
  129. }
  130. /// <summary>
  131. /// 获取XML文件的内容
  132. /// </summary>
  133. /// <param name="fileName">XML文件名</param>
  134. /// <param name="sectionName">对应的XPath</param>
  135. /// <param name="rawType">是否不进行任何转换而返回</param>
  136. /// <returns>XmlNode</returns>
  137. public static XmlNode LoadXmlNodeFromFile(string fileName, string sectionName, bool rawType) {
  138. var doc = new XmlDocument();
  139. LoadXmlFile(doc, fileName);
  140. var xmlNode = doc.SelectSingleNode(sectionName);
  141. xmlNode = xmlNode?.CloneNode(true);
  142. if(!rawType && xmlNode is XmlDocument) {
  143. xmlNode = ((XmlDocument)xmlNode).DocumentElement;
  144. }
  145. return xmlNode;
  146. }
  147. /// <summary>
  148. /// 分析XML字符串内容
  149. /// </summary>
  150. /// <param name="xmlString">XML字符串</param>
  151. /// <param name="sectionName">对应的XPath</param>
  152. /// <returns>XmlNode</returns>
  153. public static XmlNode LoadXmlNodeFromString(string xmlString, string sectionName) {
  154. var doc = new XmlDocument();
  155. doc.LoadXml(xmlString);
  156. var xmlNode = doc.SelectSingleNode(sectionName);
  157. return xmlNode?.CloneNode(true);
  158. }
  159. internal static IConfigSetting LoadConfigSettingFromAssemblies(Assembly coreAssembly, List<Assembly> assemblies, IConfigSetting appSetting, IConfigSetting userRootSetting, string[] resnamePatterns = null) {
  160. return LoadConfigSettingFromAssemblies(new []{ coreAssembly }, assemblies, appSetting, userRootSetting, resnamePatterns);
  161. }
  162. internal static IConfigSetting LoadConfigSettingFromAssemblies(Assembly[] coreAssemblies, List<Assembly> assemblies, IConfigSetting appSetting, IConfigSetting userRootSetting, string[] resnamePatterns = null) {
  163. if(assemblies == null) {
  164. assemblies = new List<Assembly>();
  165. }
  166. var theAssembly = typeof(ObjectService).Assembly;
  167. var theName = theAssembly.FullName;
  168. var refAssemblies = TypeHelper.FindAssemblyChildren(theAssembly);//仅处理有引用本类库的程序集/或处理本类库
  169. if(assemblies == null) {
  170. assemblies = refAssemblies;
  171. } else {
  172. assemblies = TypeHelper.SortAssemblies(assemblies, refAssemblies);
  173. //把核心Assembly放在最前面
  174. for (var i = coreAssemblies.Length - 1; i >= 0; i--) {
  175. var coreAssembly = coreAssemblies[i];
  176. assemblies.Remove(coreAssembly);
  177. assemblies.Insert(0, coreAssembly);
  178. }
  179. }
  180. var resources = new List<ConfigResource>();
  181. //获取由ConfigResourceAttribute定义的资源文件
  182. foreach (var assembly in assemblies) {
  183. var attributes = assembly.GetCustomAttributes(typeof(ConfigResourceAttribute), true) as ConfigResourceAttribute[];
  184. if (attributes != null && attributes.Length > 0) {
  185. var attributeList = new List<ConfigResourceAttribute>(attributes);
  186. attributeList.Sort((x, y) => x.Index - y.Index);
  187. foreach (var attribute in attributeList) {
  188. if (!resources.Exists(x => x.ResourceName == attribute.Resource && x.Assembly == assembly)) {
  189. resources.Add(new ConfigResource { ResourceName = attribute.Resource, Assembly = assembly });
  190. }
  191. }
  192. }
  193. }
  194. //获取由resnamePatterns指定的资源
  195. if(resnamePatterns != null && resnamePatterns.Length > 0) {
  196. foreach(var ass in assemblies) {
  197. if(ass.IsDynamic) {
  198. continue;
  199. }
  200. var names = ass.GetManifestResourceNames();
  201. if(names != null && names.Length > 0) {
  202. var nameList = names.Where(x => resnamePatterns.Any(y => y != null && x.EndsWith(y)));
  203. foreach(var name in nameList) {
  204. if (!resources.Exists(x => x.ResourceName == name && x.Assembly == ass)) {
  205. resources.Add(new ConfigResource { ResourceName = "res://" + name, Assembly = ass });
  206. }
  207. }
  208. }
  209. }
  210. }
  211. //创建并合并这些资源文件
  212. var rootSetting = CreateFromXmlString($"<configuration><{RootSettingName} /></configuration>");
  213. foreach (var resource in resources) {
  214. var configSetting = CreateFromXmlSource(resource.ResourceName, resource.Assembly);
  215. rootSetting.Merge(configSetting);
  216. }
  217. if (userRootSetting != null) {
  218. userRootSetting = userRootSetting.GetRootSetting();
  219. }
  220. if (userRootSetting == null) {
  221. userRootSetting = appSetting;
  222. }
  223. if (userRootSetting != null) {
  224. var mergeSetting = rootSetting;
  225. if (userRootSetting.SettingName == RootSettingName) {
  226. mergeSetting = rootSetting[RootSettingName];
  227. }
  228. mergeSetting?.Merge(userRootSetting);
  229. }
  230. return rootSetting;
  231. }
  232. /// <summary>
  233. /// 载入XML文件内容
  234. /// </summary>
  235. /// <param name="doc">XmlDocument</param>
  236. /// <param name="fileName">文件名</param>
  237. private static void LoadXmlFile(XmlDocument doc, string fileName) {
  238. doc.Load(fileName);
  239. }
  240. private class ConfigResource
  241. {
  242. public string ResourceName { get; set; }
  243. public Assembly Assembly { get; set; }
  244. }
  245. }
  246. }