前言

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

           //读取appsetting
var appSettingValue = ConfigurationManager.AppSettings["KEY"];
//读取connectionstring
var connectionValue = 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 = 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 = 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" value="value"/>

总结

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

StackExchange.Redis.Extensions.Core 源码解读之 Configuration用法的更多相关文章

  1. spring core源码解读之ASM4用户手册翻译之一asm简介

    第一章:ASM介绍 1.1 ASM动机: 程序的分析,生成,转换技术可以应用到许多场景: 1.程序分析,从简单的语法解析到完整的语义分析,可以应用在程序中找到潜在的bug,发现无用的代码,工程代码的逆 ...

  2. asp.net core源码飘香:Configuration组件

    简介: 这是一个基础组件,是一个统一的配置模型,配置可以来源于配置文件(json文件,xml文件,ini文件),内存对象,命令行参数,系统的环境变量又或者是你自己扩展的配置源,该组件将各个配置源的数据 ...

  3. jvm源码解读--16 cas 用法解析

    CAS的意思是campare and sweep比较交换 这个如果不用代码会比较抽象,那么在源码中进行解释 void ATTR ObjectMonitor::enter(TRAPS) { // The ...

  4. c# redis 操作类库推荐:StackExchange.Redis.Extensions

    StackExchange是一个优秀的c# redis客户端,但是存在操作略为繁琐的弊端,为了简化操作,使用 StackExchange.Redis.Extensions成为了一个非常值得推荐的选择. ...

  5. Jfinal-Plugin源码解读

    PS:cnxieyang@163.com/xieyang@e6yun.com 本文就Jfinal-plugin的源码进行分析和解读 Plugin继承及实现关系类图如下,常用的是Iplugin的三个集成 ...

  6. Jfinal启动源码解读

    本文对Jfinal的启动源码做解释说明. PS:Jfinal启动容器可基于Tomcat/Jetty等web容器启动,本文基于Jetty的启动方式做启动源码的解读和分析,tomcat类似. 入口  JF ...

  7. JFinal的启动源码解读

    本文对Jfinal的启动源码做解释说明. PS:Jfinal启动容器可基于Tomcat/Jetty等web容器启动,本文基于Jetty的启动方式做启动源码的解读和分析,tomcat类似. 入口  JF ...

  8. 《.NET 5.0 背锅案》第7集-大结局:捉拿真凶 StackExchange.Redis.Extensions 归案

    第1集:验证 .NET 5.0 正式版 docker 镜像问题 第2集:码中的小窟窿,背后的大坑,发现重要嫌犯 EnyimMemcachedCore 第3集-剧情反转:EnyimMemcachedCo ...

  9. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

随机推荐

  1. idea首次提交项目

    http://www.cnblogs.com/exmyth/p/6133289.html

  2. iframe 根据加载内容调整高度

    iframe标签代码 <iframe id="checkListFrame" name="checkListFrame"    src="Ind ...

  3. telnet: connect to address xxxxxxx: No route to host

    在要连接的服务上执行iptables -F

  4. oracle中DDL DML指什么?

    DDL create table 创建表 alter table 修改表 drop table 删除表 truncate table 删除表中所有行 create index 创建索引 drop in ...

  5. 用Gen8服务器来学习虚拟化ESXI

    虚拟化和云计算是这几年的热门技术,VMware公司是虚拟化的领头羊,小坦克我有幸在VMware从事这方面的测试工作. 本系列将会讲述我学习虚拟化的一些经历. 将会覆盖一些虚拟化产品: 比如:VMwar ...

  6. Octopus系列之js公共函数

    货币选择 ChangeCurrency(this.value) 示例 <select name="currency" id="sl_currency" c ...

  7. iOS开发UI篇—使用picker View控件完成一个简单的选餐应用

    iOS开发UI篇—使用picker View控件完成一个简单的选餐应用 一.实现效果 说明:点击随机按钮,能够自动选取,下方数据自动刷新. 二.实现思路 1.picker view的有默认高度为162 ...

  8. MVN使用随笔

    001 创建项目 mvn archetype:generate -DgroupId=com.company.push.monitor -DartifactId=push-monitor -Darche ...

  9. 1362. Classmates 2

    http://acm.timus.ru/problem.aspx?space=1&num=1362 水题,树形DP 代码: #include<iostream> #include& ...

  10. SVN - 忽略已经提交的文件

    1.在本地删除要忽略的文件 2.与资源库同步,提交删除的文件 3.忽略文件