首页 > 代码库 > StackExchange.Redis.Extensions.Core 源码解读之 Configuration用法

StackExchange.Redis.Extensions.Core 源码解读之 Configuration用法

前言

  之前接触到Redis,然后选用了对StackExchange.Redis又一层封装的StackExchange.Redis.Extensions.Core类库。阅读源代码的过程中发现了他使用Configuration实现读取自定义配置的方法。特此学习并记录。在我们日常开发中,最常用的自定义配置读取方式莫过于如下两种方式,尤其是连接数据库。

           //读取appsetting                var appSettingValue = http://www.mamicode.com/ConfigurationManager.AppSettings["KEY"];                //读取connectionstring                var connectionValue = http://www.mamicode.com/ConfigurationManager.ConnectionStrings["KEY"];

  而在使用这个类库的时候它的配置形式是这样的:

<configSections>    <section name="redisCacheClient"           type="StackExchange.Redis.Extensions.Core.Configuration.RedisCachingSectionHandler, StackExchange.Redis.Extensions.Core" />  </configSections>  <redisCacheClient allowAdmin="true" ssl="false" connectTimeout="5000" database="0" password="">    <hosts>      <add host="127.0.0.1" cachePort="6379"/>
<add host="127.0.0.1" cachePort="6380"/>
  </hosts>
</redisCacheClient>

  没错,就是自定义section,然后在读取section中详细的配置信息,如上述代码所示,sectionName=redisCacheClient,allowAdmin,ssl等都是它的配置信息。<hosts>节点比较特殊,它是一系列配置信息的集合。

代码解读

  先看一下自定义配置接口,里面就包含了 redisCacheClient中的各种属性定义

  

/// <summary>    /// 自定义配置接口    /// </summary>    public interface IRedisCachingConfiguration    {        /// <summary>        /// Redis Server的服务端口配置        /// </summary>        /// <value>        /// IP地址或者服务器名称        /// </value>        RedisHostCollection RedisHosts { get; }        /// <summary>        /// The strategy to use when executing server wide commands        /// </summary>        ServerEnumerationStrategy ServerEnumerationStrategy { get; }        /// <summary>        /// 定义是否该连接可以使用管理员权限操作,比如flush database        /// </summary>        /// <value>        ///   <c>true</c> 可以使用管理员权限; 否则, <c>false</c>.        /// </value>        bool AllowAdmin { get; }        /// <summary>        /// 是否SSL安全加密        /// </summary>        /// <value>        ///   <c>true</c> if is secure; otherwise, <c>false</c>.        /// </value>        bool Ssl { get; }        /// <summary>        /// 连接超时时间        /// </summary>        int ConnectTimeout { get; }        /// <summary>        /// 没有服务可用的时候,不会创建新连接        /// </summary>        bool AbortOnConnectFail { get; }        /// <summary>        /// Database Id        /// </summary>        /// <value>        /// database的ID,默认为0        /// </value>        int Database { get; }        /// <summary>        /// 密码        /// </summary>        string Password { get; }    }

  我们看一下类的具体实现,首先要继承自定义的接口,还要继承ConfigurationSection,这样当我们取比如说 allowAdmin的值的时候可以在内部直接调用 this["allowAdmin"]取到值了。

  /// <summary>    /// 继承自定义接口,并且继承ConfigurationSection<see cref="IRedisCachingConfiguration"/>    /// </summary>    public class RedisCachingSectionHandler : ConfigurationSection, IRedisCachingConfiguration    {                      //这里就只拿allowAdmin举例,默认是string类型,那么我们就要根据自己的需求进行数据类型转换了。这里就把string类型转换为我们想要的bool类型        [ConfigurationProperty("allowAdmin")]        public bool AllowAdmin        {            get            {                              bool result = false;                var config = this["allowAdmin"];                if (config != null)                {                    var value =http://www.mamicode.com/ config.ToString();                    if (!string.IsNullOrEmpty(value))                    {                        if (bool.TryParse(value, out result))                        {                            return result;                        }                    }                }                return result;            }        }       //其他代码
    ...
    ...
/// <summary> /// 读取配置信息,外部调用主方法 /// </summary> /// <returns></returns> public static RedisCachingSectionHandler GetConfig() { return ConfigurationManager.GetSection("redisCacheClient") as RedisCachingSectionHandler; } }

  下面我们在看一下元素集合的使用,单节点RedisHost代码如下:

/// <summary>    /// RedisHost的配置元素    /// </summary>    public class RedisHost : ConfigurationElement    {        /// <summary>        /// Gets the Redis host.        /// </summary>        /// <value>        ///获取host节点值        /// </value>        [ConfigurationProperty("host", IsRequired = true)]        public string Host        {            get            {                return this["host"] as string;            }        }        /// <summary>        /// Gets the port.        /// </summary>        /// <value>        /// 获取cachePort的值        /// </value>        [ConfigurationProperty("cachePort", IsRequired = true)]        public int CachePort        {            get            {                var config = this["cachePort"];                if (config != null)                {                    var value =http://www.mamicode.com/ config.ToString();                    if (!string.IsNullOrEmpty(value))                    {                        int result;                        if (int.TryParse(value, out result))                        {                            return result;                        }                    }                }                throw new Exception("Redis Cahe port must be number.");            }        }    }

  还需要定义一个Collection将Hosts中的内容收集起来。类似List

/// <summary>    /// Configuration Element Collection for <see cref="RedisHost"/>    /// </summary>    public class RedisHostCollection : ConfigurationElementCollection    {        /// <summary>        /// Gets or sets the <see cref="RedisHost"/> at the specified index.        /// </summary>        /// <value>        /// The <see cref="RedisHost"/>.        /// </value>        /// <param name="index">The index.</param>        /// <returns></returns>        public RedisHost this[int index]        {            //BaseGet,BaseRemoveAt,BaseAdd都是 ConfigurationElementCollection 中定义的方法            get            {                //调用BaseGet方法获取节点信息                return BaseGet(index) as RedisHost;            }            set            {                //设置的时候先删掉,在添加                if (BaseGet(index) != null)                {                    BaseRemoveAt(index);                }                BaseAdd(index, value);            }        }        /// <summary>        ///此方法需要重写,返回一个新节点        /// </summary>        /// <returns></returns>        protected override ConfigurationElement CreateNewElement()        {            return new RedisHost();        }        /// <summary>        /// 重写此方法,获取元素key        /// </summary>        /// <param name="element">元素</param>        /// <returns></returns>        protected override object GetElementKey(ConfigurationElement element)             //这里可以看到,这个key就是 Host:Port            => $"{((RedisHost) element).Host}:{((RedisHost) element).CachePort}";    }

  经过一层层的包装之后,Handler中后去Host的节点方法就很简单了。

/// <summary>        /// The host of Redis Server        /// </summary>        /// <value>        /// The ip or name        /// </value>        [ConfigurationProperty("hosts")]        public RedisHostCollection RedisHosts            => this["hosts"] as RedisHostCollection;

  我们运行程序读取一下试试:

         RedisCachingSectionHandler config = RedisCachingSectionHandler.GetConfig();            Console.WriteLine("config中的allowAdmin:" + config.AllowAdmin);            Console.WriteLine("config中的ssl:" + config.Ssl);            Console.WriteLine("config中的password:" + config.Password);            Console.WriteLine("config中的database:" + config.Database);            Console.WriteLine();            Console.WriteLine("读取Host信息如下:");            foreach (RedisHost host in config.RedisHosts)            {                Console.WriteLine($"{host.Host}:{host.CachePort}");            }            Console.Read();

  运行结果:

  技术分享

  config中的信息已经正常读取到。那么我们可以用这种方式实现读取自己自定义的配置信息啦。当然,简单的配置还是直接用 <add key="key" http://www.mamicode.com/value="value"/>

总结

  微软库已经给我们提供了太多的方法,在不知情的情况下我们往往会自己去实现。多看看开源代码对自己知识的提升还有有帮助的。这不,学会了这种配置方法,我们就可使用不仅仅ConfigurationManager这个类了。

StackExchange.Redis.Extensions.Core 源码解读之 Configuration用法