C#实现的Redis扩展项目(二次封装)
Redis在当下的互联网项目当中的普及率我想都不用多说了,本文要介绍的這个项目是基于我对Redis理解程度的基础上写的一个公共类库项目,希望对各位童鞋有所帮助,也欢迎各位对我都内容提出更好的意见。
由于本文使用了自定义配置相关的只是,如有不了解的童鞋,可以先去了解一下這方面的知识然后再来看相应的代码,這样可能想过会更好,下面正式进入正题(初次写這个东西,语言组织不合理请大家谅解)。
项目概览:
该项目主要分成两部分,配置和业务扩展两部分组成,具体项目结构如下:
自定义配置:建立配置项的目的主要是方便我们后面在web.config或者app.config中定义属于redis的单独配置区域,从而使得我们的程序配置变得简单、易读易配置,后面的介绍将不再重复说明
RedisConfiguration.cs: 作为自定义配置文件的主节点,该节点包含的属性: serviceStackConnectionStrings和stackExchangeConnectionStrings
using System.Configuration; namespace HB.Common.Caches.Configs
{
/// <summary>
/// Redis配置节点
/// </summary>
public class RedisConfiguration : ConfigurationSection
{
//<configSections>
// <section name = "redisConfiguration" type="HB.Common.Caches.Configs.RedisConfiguration, HB.Common.Caches.Configs" />
//</configSections>
//<redisConfiguration configSource = "Config\redisConfiguration.config" /> //<redisConfiguration>
// <!--连接字符串-->
// <serviceStackConnectionStrings writehost ="192.168.3.11:6379,192.168.3.11:6380" readhost="192.168.3.11:6379,192.168.3.11:6380" password="ChinaNet910111" maxwritepoolsize="200" maxreadpoolsize="200" />
//</redisConfiguration> /// <summary>
/// 节点名称
/// </summary>
private const string sectionName = "redisConfiguration"; /// <summary>
/// 获取配置信息
/// </summary>
/// <returns></returns>
public static RedisConfiguration ConfigSection()
{
return (RedisConfiguration)ConfigurationManager.GetSection(sectionName);
} /// <summary>
/// StackExchange配置节点
/// </summary>
[ConfigurationProperty("stackExchangeConnectionStrings", IsRequired = false)]
public StackExchangeConfigurationSection StackExchangeConnectionStrings
{
get
{
return (StackExchangeConfigurationSection)base["stackExchangeConnectionStrings"];
}
set
{
base["stackExchangeConnectionStrings"] = value;
}
} /// <summary>
/// ServiceStack配置节点
/// </summary>
[ConfigurationProperty("serviceStackConnectionStrings", IsRequired = false)]
public ServiceStackConfigurationSection ServiceStackConnectionStrings
{
get
{
return (ServiceStackConfigurationSection)base["serviceStackConnectionStrings"];
}
set
{
base["serviceStackConnectionStrings"] = value;
}
}
}
}
RedisConfiguration.cs
ServiceStackConfigurationSection.cs:ServiceStack插件链接字符串配置项
using System.Configuration; namespace HB.Common.Caches.Configs
{
/// <summary>
/// ServiceStack配置节点
/// </summary>
public class ServiceStackConfigurationSection : ConfigurationElement
{
//<!--连接字符串-->
//<serviceStackConnectionStrings writehost ="192.168.3.11:6379,192.168.3.11:6380" readhost="192.168.3.11:6379,192.168.3.11:6380" password="ChinaNet910111" maxwritepoolsize="200" maxreadpoolsize="200" autoStart="false" /> /// <summary>
/// 可写的Redis链接地址
/// </summary>
[ConfigurationProperty("writehost", IsRequired = false)]
public string WriteHost
{
get
{
return (string)base["writehost"];
}
set
{
base["writehost"] = value;
}
} /// <summary>
/// 可读的Redis链接地址
/// </summary>
[ConfigurationProperty("readhost", IsRequired = false)]
public string ReadHost
{
get
{
return (string)base["readhost"];
}
set
{
base["readhost"] = value;
}
} /// <summary>
/// 登陆密码
/// </summary>
[ConfigurationProperty("password", IsRequired = false)]
public string Password
{
get
{
return (string)base["password"];
}
set
{
base["password"] = value;
}
} /// <summary>
/// 最大写链接数
/// </summary>
[ConfigurationProperty("maxwritepoolsize", IsRequired = false, DefaultValue = )]
public int MaxWritePoolSize
{
get
{
return (int)base["maxwritepoolsize"];
}
set
{
base["maxwritepoolsize"] = value;
}
} /// <summary>
/// 最大读链接数
/// </summary>
[ConfigurationProperty("maxreadpoolsize", IsRequired = false, DefaultValue = )]
public int MaxReadPoolSize
{
get
{
return (int)base["maxreadpoolsize"];
}
set
{
base["maxreadpoolsize"] = value;
}
} /// <summary>
///
/// </summary>
[ConfigurationProperty("autoStart", IsRequired = false, DefaultValue = true)]
public bool AutoStart
{
get
{
return (bool)base["autoStart"];
}
set
{
base["autoStart"] = value;
}
}
}
}
ServiceStackConfigurationSection.cs
StackExchangeConfigurationSection.cs:StackExchange.Redis的链接字符串属性节点
using System.Configuration; namespace HB.Common.Caches.Configs
{
/// <summary>
/// StackExchange节点配置
/// </summary>
public class StackExchangeConfigurationSection : ConfigurationElement
{
// <!--连接字符串-->
// <connectionStrings host = "192.168.3.11:6379,192.168.3.11:6380" password="ChinaNet910111" /> /// <summary>
/// 监听主机
/// </summary>
[ConfigurationProperty("host", IsRequired = true)]
public string Host
{
get
{
return (string)base["host"];
}
set
{
base["host"] = value;
}
} /// <summary>
/// 密码
/// </summary>
[ConfigurationProperty("password", IsRequired = false)]
public string Password
{
get
{
return (string)base["password"];
}
set
{
base["password"] = value;
}
}
}
}
StackExchangeConfigurationSection.cs
业务扩展类:
ServiceStackManager.cs:该管理类ServiceStack的扩展,可以对Redis进行增、删、改、查等一系列操作,具体实现如下
using HB.Common.Caches.Configs;
using ServiceStack.Redis; namespace HB.Common.Caches.Redis
{
/// <summary>
/// Redis客户端管理类
/// </summary>
public class ServiceStackManager
{
/// <summary>
/// 线程同步变量
/// </summary>
private static object synObj = new object(); /// <summary>
/// redis链接池管理对象
/// </summary>
private static PooledRedisClientManager _instance = null; /// <summary>
/// 链接字符串
/// </summary>
private static ServiceStackConfigurationSection ConnectionStrings
{
get
{
var configSection = RedisConfiguration.ConfigSection();
return configSection.ServiceStackConnectionStrings;
}
} /// <summary>
/// 私有构造函数,静止外部通过new关键字来创建该对象实例
/// </summary>
private ServiceStackManager()
{ } /// <summary>
/// 获取redis链接池管理对象实例
/// 实例发生变化的集中情况:
/// 1.实例为空
/// 2.配置文件发生变化
/// </summary>
private static PooledRedisClientManager GetInstance()
{
if (_instance == null)
{
lock (synObj)
{
if (_instance == null)
{
var managerConfig = new RedisClientManagerConfig()
{
AutoStart = ConnectionStrings.AutoStart,
MaxReadPoolSize = ConnectionStrings.MaxReadPoolSize,
MaxWritePoolSize = ConnectionStrings.MaxWritePoolSize
}; string[] readServerList = GetHostList(ConnectionStrings.ReadHost);
string[] writeServerList = GetHostList(ConnectionStrings.WriteHost);
_instance = new PooledRedisClientManager(readServerList, writeServerList, managerConfig);
}
}
}
return _instance;
} /// <summary>
/// 客户端缓存操作对象实例
/// </summary>
public static IRedisClient GetClient(int dbIndex = )
{
var clientManager = GetInstance();
var client = clientManager.GetClient();
if (!string.IsNullOrEmpty(ConnectionStrings.Password))
client.Password = ConnectionStrings.Password; client.Db = dbIndex;
return client;
} /// <summary>
///
/// </summary>
/// <param name="hostStrings"></param>
/// <returns></returns>
private static string[] GetHostList(string hostStrings)
{
if (string.IsNullOrWhiteSpace(hostStrings))
return new string[] { }; return hostStrings.Split(',');
}
}
}
ServiceStackManager.cs
StackExchangeManager.cs:该管理类是对StackExchange.Redis增删改查等操作的扩展
using HB.Common.Caches.Configs;
using log4net;
using Newtonsoft.Json;
using StackExchange.Redis; namespace HB.Common.Caches.Redis
{
/// <summary>
/// StackExchangeManager
///
/// 在StackExchange.Redis中最重要的对象是ConnectionMultiplexer类, 它存在于StackExchange.Redis命名空间中。
/// 这个类隐藏了Redis服务的操作细节,ConnectionMultiplexer类做了很多东西, 在所有调用之间它被设计为共享和重用的。
/// 不应该为每一个操作都创建一个ConnectionMultiplexer 。 ConnectionMultiplexer是线程安全的 , 推荐使用下面的方法。
/// 在所有后续示例中 , 都假定你已经实例化好了一个ConnectionMultiplexer类,它将会一直被重用 ,
/// 现在我们来创建一个ConnectionMultiplexer实例。它是通过ConnectionMultiplexer.Connect 或者 ConnectionMultiplexer.ConnectAsync,
/// 传递一个连接字符串或者一个ConfigurationOptions 对象来创建的。
/// 连接字符串可以是以逗号分割的多个服务的节点.
///
/// 注意 :
/// ConnectionMultiplexer 实现了IDisposable接口当我们不再需要是可以将其释放的 , 这里我故意不使用 using 来释放他。
/// 简单来讲创建一个ConnectionMultiplexer是十分昂贵的 , 一个好的主意是我们一直重用一个ConnectionMultiplexer对象。
/// 一个复杂的的场景中可能包含有主从复制 , 对于这种情况,只需要指定所有地址在连接字符串中(它将会自动识别出主服务器)
/// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("server1:6379,server2:6379");
/// 假设这里找到了两台主服务器,将会对两台服务进行裁决选出一台作为主服务器来解决这个问题 , 这种情况是非常罕见的 ,我们也应该避免这种情况的发生。
///
///
/// 这里有个和 ServiceStack.Redis 大的区别是没有默认的连接池管理了。没有连接池自然有其利弊,最大的好处在于等待获取连接的等待时间没有了,
/// 也不会因为连接池里面的连接由于没有正确释放等原因导致无限等待而处于死锁状态。缺点在于一些低质量的代码可能导致服务器资源耗尽。不过提供连接池等阻塞和等待的手段是和作者的设计理念相违背的。StackExchange.Redis这里使用管道和多路复用的技术来实现减少连接
///
/// 参考:http://www.cnblogs.com/Leo_wl/p/4968537.html
/// </summary>
public class StackExchangeManager
{
/// <summary>
/// 线程同步变量
/// </summary>
private static object syncObj = new object(); /// <summary>
/// redis链接池管理对象
/// </summary>
private static ConnectionMultiplexer _instance = null; /// <summary>
/// 日志记录器
/// </summary>
private static readonly ILog _log = LogManager.GetLogger(typeof(StackExchangeManager)); /// <summary>
/// 私有构造函数,限制不允许通过new 来实例化该对象
/// </summary>
private StackExchangeManager()
{ } /// <summary>
/// 使用一个静态属性来返回已连接的实例
/// 实例发生变化的几种情况:
/// 1.实例为空
/// 2.连接关闭
/// 3.文件发生变化时
/// </summary>
private static ConnectionMultiplexer GetInstance()
{
if (_instance == null || !_instance.IsConnected)
{
lock (syncObj)
{
if (_instance == null || !_instance.IsConnected)
{
var configSection = RedisConfiguration.ConfigSection();
var stackExchangeConnectionStrings = configSection.StackExchangeConnectionStrings;
_instance = ConnectionMultiplexer.Connect(stackExchangeConnectionStrings.Host);
}
}
}
_instance.ErrorMessage += MuxerErrorMessage;
_instance.HashSlotMoved += MuxerHashSlotMoved;
_instance.InternalError += MuxerInternalError;
_instance.ConnectionFailed += MuxerConnectionFailed;
_instance.ConnectionRestored += MuxerConnectionRestored;
_instance.ConfigurationChanged += MuxerConfigurationChanged;
return _instance;
} /// <summary>
/// 客户端缓存操作对象实例
/// <paramref name="dbIndex"/>
/// </summary>
public static IDatabase GetDatabase(int dbIndex = -)
{
var instance = GetInstance();
return instance.GetDatabase(dbIndex);
} /// <summary>
/// 配置更改时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)
{
_log.Warn($"Muxer Configuration Changed=>EndPoint:{JsonConvert.SerializeObject(e.EndPoint)}");
} /// <summary>
/// 发生错误时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
{
_log.Error($"Muxer ErrorMessage=>RedisErrorEventArgs:{JsonConvert.SerializeObject(e)}");
} /// <summary>
/// 重新建立连接之前的错误
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
{
_log.Error($"Muxer Connection Restored=>ConnectionFailedEventArgs:{JsonConvert.SerializeObject(e)}");
} /// <summary>
/// 连接失败 , 如果重新连接成功你将不会收到这个通知
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
{
_log.Error($"Muxer Connection Failed=>ConnectionFailedEventArgs:{JsonConvert.SerializeObject(e)}");
} /// <summary>
/// 更改集群
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
{
_log.Error($"Muxer HashSlot Moved=>HashSlotMovedEventArgs:{JsonConvert.SerializeObject(e)}");
} /// <summary>
/// redis类库错误
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
{
_log.Error($"Muxer Internal Error=>InternalErrorEventArgs:{JsonConvert.SerializeObject(e)}");
}
}
}
StackExchangeManager.cs
RedisSessionManager.cs:主要是StackExchange.Redis插件实现的用户登陆会话管理类
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Web; namespace HB.Common.Caches.Redis
{
/// <summary>
/// Redis Session 管理类
/// </summary>
public class RedisSessionManager
{
/// <summary>
/// 获取并设置在会话状态提供程序终止会话之前各请求之间所允许的时间(以分钟为单位)
/// </summary>
public int TimeOut { get; set; } /// <summary>
/// 获取一个值,该值指示会话是否为只读
/// </summary>
public bool IsReadOnly { get; set; } /// <summary>
/// HttpContext
/// </summary>
private HttpContextBase HttpContext { get; set; } /// <summary>
/// SessionId标识符
/// </summary>
public static string SessionName = "HB.Redis.SessionId"; /// <summary>
/// 缓存
/// </summary>
private static IDatabase _cache = StackExchangeManager.GetDatabase(); /// <summary>
/// 获取会话状态集合中的项数
/// </summary>
public long Count
{
get
{
return _cache.HashLength(SessionId);
}
} /// <summary>
/// 静止无参的构造函数被实例化
/// </summary>
private RedisSessionManager() { } /// <summary>
/// 构造函数
/// </summary>
/// <param name="httpRequst">客户端的请求信息</param>
/// <param name="isReadOnly">
/// 获取一个值,该值指示会话是否为只读
/// 说明:true 表示只读;false 表示读写
/// 默认:true
/// </param>
/// <param name="timeout">
/// 会话有效期
/// 单位:分钟
/// 默认:20分钟
/// </param>
public RedisSessionManager(HttpContextBase httpContext, bool isReadOnly = true, int timeout = )
{
TimeOut = timeout;
IsReadOnly = isReadOnly;
HttpContext = httpContext;
if (_cache.KeyExists(SessionId))
{
//设置缓存有效期(第二次以上通过這里更新缓存有效期)
_cache.KeyExpire(SessionId, expiry: DateTime.Now.AddMinutes(TimeOut));
}
} /// <summary>
/// 获取并设置在会话状态提供程序终止会话之前各请求之间所允许的时间(以分钟为单位)
/// </summary>
/// <returns></returns>
public string SessionId
{
get
{
var cookie = HttpContext.Request.Cookies.Get(SessionName);
if (cookie == null || string.IsNullOrEmpty(cookie.Value))
{
string newSessionID = Guid.NewGuid().ToString();
var newCookie = new HttpCookie(SessionName, newSessionID);
newCookie.HttpOnly = IsReadOnly;
newCookie.Expires = DateTime.Now.AddMinutes(TimeOut);
HttpContext.Response.Cookies.Add(newCookie);
return newSessionID;
}
else
{
return cookie.Value;
}
}
} /// <summary>
/// 按名称获取或者设置会话值
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public object this[string name]
{
get
{
return _cache.HashGet(SessionId, name);
}
set
{
var isKeyExists = _cache.KeyExists(SessionId);//缓存是否存在
var hashValue = JsonConvert.SerializeObject(value);
var isSuccess = _cache.HashSet(SessionId, name, hashValue);
if (isSuccess && !isKeyExists)
{
//设置缓存有效期(第一次插入缓存的时候通过這里设置缓存的有效期)
_cache.KeyExpire(SessionId, expiry: DateTime.Now.AddMinutes(TimeOut));
}
}
} /// <summary>
/// 判断会话中是否存在指定key
/// </summary>
/// <param name="name">键值</param>
/// <returns></returns>
public bool Exists(string name)
{
return _cache.HashExists(SessionId, name);
} /// <summary>
/// 从会话集合中移除所有的键值
/// </summary>
/// <returns></returns>
public bool Clear()
{
return _cache.KeyDelete(SessionId);
} /// <summary>
/// 删除会话状态集合中的指定项
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public bool Remover(string name)
{
return _cache.HashDelete(SessionId, name);
}
}
}
RedisSessionManager.cs
有需要源码的同学,可以给我留言或者发到我得邮箱。
C#实现的Redis扩展项目(二次封装)的更多相关文章
- centos7上安装redis以及PHP安装redis扩展(二)
PHP 使用 Redis 安装 开始在 PHP 中使用 Redis 前, 我们需要确保已经安装了 redis 服务及 PHP redis 驱动,且你的机器上能正常使用 PHP. 接下来让我们安装 PH ...
- mini Redis(项目 二)
一个仿Redis的内存数据库(主要用来做命令解析)服务端, 客户端使用的开源工具 : https://dom4j.github.io/ github:https://github.com/h ...
- PHPstudy安装redis扩展
PHPstudy安装redis扩展 第一步:查看PHP版本(phpinfo) 第二步:下载所需的扩展(http://pecl.php.net/package/redis . http://wi ...
- 从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建
从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建 废话不说,直接撸步骤!!! 1.创建主项目:ncc-parent 选择maven创建项目,注意在创建项目中,packing选择 ...
- windows下php7.1安装redis扩展以及redis测试使用全过程
最近做项目,需要用到redis相关知识.在Linux下,redis扩展安装起来很容易,但windows下还是会出问题的.因此,特此记下自己实践安装的整个过程,以方便后来人. 一,php中redis扩展 ...
- nginx + php + mysql安装、配置、自启动+redis扩展
用过了apache就想着用用nginx,网上教程其实很多,但是受服务器版本等限制,每个人遇到的问题也不一样,先记录下我的 一.安装依赖 yum -y install gcc zlib zlib-dev ...
- windows下php7.1安装redis扩展以及redis测试使用全过程(转)
最近做项目,需要用到redis相关知识.在Linux下,redis扩展安装起来很容易,但windows下还是会出问题的.因此,特此记下自己实践安装的整个过程,以方便后来人. 一,php中redis扩展 ...
- Linux上给php配置redis扩展
说明,在项目开发中难免会遇到redis中,那我应该如何配置redis这样的一个扩展呢,看下面流程: 一.安装Redis PHP在安装redis扩展时,难免要看一下官网下载安装流程,链接如下: http ...
- Windows下安装Redis服务及安装PHP的Redis扩展
Redis是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 它通常被称为数据结构服务器,因为值(valu ...
随机推荐
- Reverse Words in a String III
Given a string, you need to reverse the order of characters in each word within a sentence while sti ...
- 退出psql时,报psql_history的错
数据库版本:Enterprisedb 9.2(postgreSQL) 错误如下所示: postgres=# exitcould not save history to file "/opt/ ...
- Python3常用学习网站总结(随时更新)
Python资源大全 http://python.jobbole.com/84464/ https://github.com/jobbole/awesome-python-cn scrapy: h ...
- zoj1871steps 数学 水
zoj1871 题目大意 ...
- git仓库管理笔录
Git是目前世界上最先进的分布式版本控制系统(没有之一). 小明做了个个人博客,放到了Git 仓库里面.第二天换了台电脑,只需要 git clone 克隆一下git 远程仓库的代码到本地即可.然后他 ...
- Java面向对象 String 基本数据类型对象包装类
Java面向对象 String 知识概要: (1)String的用法详解 (2)基本数据类型对象包装类 String 顾名思义,该类主要是对字符串 ...
- Another app is currently holding the yum lock; waiting for it to exit 解决方法
Another app is currently holding the yum lock; waiting for it to exit... The other application is: P ...
- Android 双击退出程序实现(有侧滑界面)
大家好,今天带来双击退出程序实现方法,我知道,网上也是有许多关于双击退出程序实现的方法,所以,听见当然是给大家带来不一样的双击退出的实现方法. 首先带来的便是关于onKeyDown和onKeyPres ...
- 从头编写 asp.net core 2.0 web api 基础框架 (5) EF CRUD
第1部分:http://www.cnblogs.com/cgzl/p/7637250.html 第2部分:http://www.cnblogs.com/cgzl/p/7640077.html 第3部分 ...
- python数据结构之树和二叉树(先序遍历、中序遍历和后序遍历)
python数据结构之树和二叉树(先序遍历.中序遍历和后序遍历) 树 树是\(n\)(\(n\ge 0\))个结点的有限集.在任意一棵非空树中,有且只有一个根结点. 二叉树是有限个元素的集合,该集合或 ...