自定义ConfigurationSection,创建多个嵌套的ConfigurationElementCollection节点
由于接口地址都是固定的,所以想到使用自定义节点,来将接口都配置到web.config中。
很快,v1.0版本出炉:
public class RequestConfigSection : ConfigurationSection { [ConfigurationProperty("sources", IsDefaultCollection = true)] [ConfigurationCollection(typeof(RequestConfigSourceCollection), AddItemName = "add")] public RequestConfigSourceCollection ConfigCollection { get { return (RequestConfigSourceCollection)this["sources"]; } set { this["sources"] = value; } } } public class RequestConfigSourceCollection : ConfigurationElementCollection { /// <summary> /// 创建新元素 /// </summary> /// <returns></returns> protected override ConfigurationElement CreateNewElement() { return new RequestConfigSource(); } /// <summary> /// 获取元素的键 /// </summary> /// <param name="element"></param> /// <returns></returns> protected override object GetElementKey(ConfigurationElement element) { return ((RequestConfigSource)element).Name; } /// <summary> /// 获取所有键 /// </summary> public IEnumerable<string> AllKeys { get { return BaseGetAllKeys().Cast<string>(); } } /// <summary> /// 索引器 /// </summary> /// <param name="name"></param> /// <returns></returns> public new RequestConfigSource this[string name] { get { return (RequestConfigSource)BaseGet(name); } } } public class RequestConfigSource : ConfigurationElement { /// <summary> /// 名称 /// </summary> [ConfigurationProperty("name")] public string Name { get { return (string)this["name"]; } set { this["name"] = value; } } /// <summary> /// 地址 /// </summary> [ConfigurationProperty("url")] public string Url { get { return (string)this["url"]; } set { this["url"] = value; } } /// <summary> /// 访问类型 /// </summary> [ConfigurationProperty("type")] public RequestType RequestType { get { return (RequestType)Enum.Parse(typeof(RequestType), this["type"].ToString(), true); } set { this["type"] = value; } } }
在web.config中的配置方式为:
<apiRequestConfig> <sources> <add name="..." url="..." type="POST" /> <add name="..." url="..." type="POST" /> <add name="..." url="..." type="POST" /> </sources> </apiRequestConfig>
这时候又看了一遍需求文档,发现有说明不同平台的接口地址是不一样的,但接口做的事情是一样的。
然后就开始想,如果接着在下边追加,则不同平台的同一接口的名称是不能相同的。
所以想到的理想的配置方式为:
<apiRequestConfig> <sources platform="android"> <add name="..." url="..." type="POST" /> <add name="..." url="..." type="POST" /> <add name="..." url="..." type="POST" /> </sources> <sources platform="ios"> <add name="..." url="..." type="POST" /> <add name="..." url="..." type="POST" /> <add name="..." url="..." type="POST" /> </sources> </apiRequestConfig>
但是sources 名称的节点只能出现一次…好吧,蛋疼了。
研究尝试了一上午也没有找到合适的解决方式,又懒得再重新写一套代码来读取XML,…开始在网上搜解决方案
用中文做关键字找不着…翻了墙,用英文来当关键字 one or more ConfigurationElementCollection…
最终在一老外的博客里找到了一个替代的解决方案,最终的配置为:
<apiRequestConfig> <requestConfigs> <request platform="android"> <sources> <add name="..." url="..." type="POST" /> <add name="..." url="..." type="POST" /> <add name="..." url="..." type="POST" /> </sources> </request> <request platform="ios"> <sources> <add name="..." url="..." type="POST" /> <add name="..." url="..." type="POST" /> <add name="..." url="..." type="POST" /> </sources> </request> </requestConfigs> </apiRequestConfig>
C#代码如下:
public class RequestConfigSection : ConfigurationSection { [ConfigurationProperty("requestConfigs", IsDefaultCollection = true)] [ConfigurationCollection(typeof(RequestConfigTypeCollection), AddItemName = "request")] public RequestConfigTypeCollection ConfigCollection { get { return (RequestConfigTypeCollection)this["requestConfigs"]; } set { this["requestConfigs"] = value; } } /// <summary> /// 根据平台和名称获取请求配置信息 /// </summary> /// <param name="name"></param> /// <param name="platform"></param> /// <returns></returns> public RequestConfigSource GetRequestConfigSource(string platform, string name) { return ConfigCollection[platform].SourceCollection[name]; } } public class RequestConfigTypeCollection : ConfigurationElementCollection { /// <summary> /// 创建新元素 /// </summary> /// <returns></returns> protected override ConfigurationElement CreateNewElement() { return new RequestConfigType(); } /// <summary> /// 获取元素的键 /// </summary> /// <param name="element"></param> /// <returns></returns> protected override object GetElementKey(ConfigurationElement element) { return ((RequestConfigType)element).Platform; } /// <summary> /// 获取所有键 /// </summary> public IEnumerable<string> AllKeys { get { return BaseGetAllKeys().Cast<string>(); } } /// <summary> /// 索引器 /// </summary> /// <param name="name"></param> /// <returns></returns> public new RequestConfigType this[string platform] { get { return (RequestConfigType)BaseGet(platform); } } } public class RequestConfigType : ConfigurationElement { /// <summary> /// 获取全部请求配置信息 /// </summary> /// <returns></returns> public RequestConfigSource[] GetAllRequestSource() { var keys = this.SourceCollection.AllKeys; return keys.Select(name => this.SourceCollection[name]).ToArray(); } /// <summary> /// 平台标识 /// </summary> [ConfigurationProperty("platform")] public string Platform { get { return (string)this["platform"]; } set { this["platform"] = value; } } [ConfigurationProperty("sources", IsDefaultCollection = true)] [ConfigurationCollection(typeof(RequestConfigSourceCollection), AddItemName = "add")] public RequestConfigSourceCollection SourceCollection { get { return (RequestConfigSourceCollection)this["sources"]; } set { this["sources"] = value; } } } public class RequestConfigSourceCollection : ConfigurationElementCollection { /// <summary> /// 创建新元素 /// </summary> /// <returns></returns> protected override ConfigurationElement CreateNewElement() { return new RequestConfigSource(); } /// <summary> /// 获取元素的键 /// </summary> /// <param name="element"></param> /// <returns></returns> protected override object GetElementKey(ConfigurationElement element) { return ((RequestConfigSource)element).Name; } /// <summary> /// 获取所有键 /// </summary> public IEnumerable<string> AllKeys { get { return BaseGetAllKeys().Cast<string>(); } } /// <summary> /// 索引器 /// </summary> /// <param name="name"></param> /// <returns></returns> public new RequestConfigSource this[string name] { get { return (RequestConfigSource)BaseGet(name); } } } /// <summary> /// 请求的配置信息 /// </summary> public class RequestConfigSource : ConfigurationElement { /// <summary> /// 名称 /// </summary> [ConfigurationProperty("name")] public string Name { get { return (string)this["name"]; } set { this["name"] = value; } } /// <summary> /// 地址 /// </summary> [ConfigurationProperty("url")] public string Url { get { return (string)this["url"]; } set { this["url"] = value; } } /// <summary> /// 访问类型 /// </summary> [ConfigurationProperty("type")] public RequestType RequestType { get { return (RequestType)Enum.Parse(typeof(RequestType), this["type"].ToString(), true); } set { this["type"] = value; } } }
本人的开发环境为 .net framework 4.0
最初RequestConfigSection 类中的ConfigCollection 和 RequestConfigType 类中的SourceCollection 没有定义ConfigurationCollection特性
而是在RequestConfigTypeCollection和RequestConfigTypeCollection 中重载了ElementName属性,返回子级的节点名。
结果抛出节点名未定义的异常…
改由特性ConfigurationCollection定义,并给特性属性AddItemName赋值为子级的节点名 解决…