分享

自定义ConfigurationSection,创建多个嵌套的ConfigurationElementCollection节点

 江江385 2016-11-25

本人现在在一家游戏公司,最近在做一个项目,需要做一个GM的管理后台,需要调用其他公司提供的接口,来实现后台管理的操作

由于接口地址都是固定的,所以想到使用自定义节点,来将接口都配置到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 特性

而是在 RequestConfigTypeCollectionRequestConfigTypeCollection 中重载了 ElementName 属性,返回子级的节点名。

结果抛出节点名未定义的异常…

改由特性 ConfigurationCollection 定义,并给特性属性 AddItemName 赋值为子级的节点名 解决…

老外博客地址: http://tneustaedter./2011/09/how-to-create-one-or-more-nested.html 需要FQ访问

或者直接看这儿,俺给Copy出来了: http://www.cnblogs.com/efenghuo/articles/4022836.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约