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扩展项目(二次封装)的更多相关文章

  1. centos7上安装redis以及PHP安装redis扩展(二)

    PHP 使用 Redis 安装 开始在 PHP 中使用 Redis 前, 我们需要确保已经安装了 redis 服务及 PHP redis 驱动,且你的机器上能正常使用 PHP. 接下来让我们安装 PH ...

  2. mini Redis(项目 二)

    一个仿Redis的内存数据库(主要用来做命令解析)服务端,  客户端使用的开源工具 : https://dom4j.github.io/     github:https://github.com/h ...

  3. PHPstudy安装redis扩展

    PHPstudy安装redis扩展 第一步:查看PHP版本(phpinfo) 第二步:下载所需的扩展(http://pecl.php.net/package/redis   .   http://wi ...

  4. 从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建

    从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建 废话不说,直接撸步骤!!! 1.创建主项目:ncc-parent 选择maven创建项目,注意在创建项目中,packing选择 ...

  5. windows下php7.1安装redis扩展以及redis测试使用全过程

    最近做项目,需要用到redis相关知识.在Linux下,redis扩展安装起来很容易,但windows下还是会出问题的.因此,特此记下自己实践安装的整个过程,以方便后来人. 一,php中redis扩展 ...

  6. nginx + php + mysql安装、配置、自启动+redis扩展

    用过了apache就想着用用nginx,网上教程其实很多,但是受服务器版本等限制,每个人遇到的问题也不一样,先记录下我的 一.安装依赖 yum -y install gcc zlib zlib-dev ...

  7. windows下php7.1安装redis扩展以及redis测试使用全过程(转)

    最近做项目,需要用到redis相关知识.在Linux下,redis扩展安装起来很容易,但windows下还是会出问题的.因此,特此记下自己实践安装的整个过程,以方便后来人. 一,php中redis扩展 ...

  8. Linux上给php配置redis扩展

    说明,在项目开发中难免会遇到redis中,那我应该如何配置redis这样的一个扩展呢,看下面流程: 一.安装Redis PHP在安装redis扩展时,难免要看一下官网下载安装流程,链接如下: http ...

  9. Windows下安装Redis服务及安装PHP的Redis扩展

    Redis是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 它通常被称为数据结构服务器,因为值(valu ...

随机推荐

  1. 架构师之路-在Dubbo中开发REST风格的远程调用

    架构师之路:从无到有搭建中小型互联网公司后台服务架构与运维架构 http://www.roncoo.com/course/view/ae1dbb70496349d3a8899b6c68f7d10b 概 ...

  2. ASP.Net MVC 布局页 模板页 使用方法详细说明

    一.Views文件夹 -> Shared文件夹下的 _Layout.cshtml 母版页 @RenderBody 当创建基于_Layout.cshtml布局页面的视图时,视图的内容会和布局页面合 ...

  3. string使用

    一.list和string转化 List转字符串,用逗号隔开 List<string> list = new List<string>();list.Add("a&q ...

  4. 【NOIP2015提高组】Day2 T2 子串

    题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问 ...

  5. ClassLoader 工作机制

    ClassLoader 采用上级委托接待机制加载 class JVM 平台提供三层 ClassLoader 1.Bootstrap ClassLoader:主要加载 JVM 自身工作需要的类 2.Ex ...

  6. JAVA中java.util.Date、java.sql.Timestamp和String之间的互相转换

    java.util.Date与的String互转 java.util.Date---->String /** * 将java.util.Date对象转化为String字符串 * @param d ...

  7. jQuery实现用户输入自动完成功能

    jQuery实现用户输入自动完成功能 利用jQuery UI中Auto-complete插件实现输入自动完成功能,大家在使用诸如淘宝.京东等电商平台搜索商品时,往往只要输入商品的一些特殊字符,就可以显 ...

  8. LeetCode 153. Find Minimum in Rotated Sorted Array (在旋转有序数组中找到最小值)

    Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e. ...

  9. 对Java原子类AtomicInteger实现原理的一点总结

    java原子类不多,包路径位于:java.util.concurrent.atomic,大致有如下的类: java.util.concurrent.atomic.AtomicBoolean java. ...

  10. JS中的单引号和双引号

    JS里面的单引号和双引号可以同时使用,但是要遵循一定的准则. 最外面用了双引号了,那么里面就不能再用双引号了,因为引号是成双对的,浏览器读到一个双引号后,到第2个双引号时才算结束:同理,浏览器读到一个 ...