C#开发微信门户及应用(48) - 在微信框架中整合CacheManager 缓存框架
在我们的很多框架或者项目应用中,缓存在一定程度上可以提高程序的响应速度,以及减轻服务器的承载压力,因此在一些地方我们都考虑引入缓存模块,这篇随笔介绍使用开源缓存框架CacheManager来实现数据的缓存,在微信开发框架中,我们有一些常用的处理也需要应用到缓存,因此本随笔以微信框架为例介绍缓存的实际使用,实际上,在我们很多框架中,如混合式开发框架、Web开发框架、Bootstrap开发框架中,这个模块都是通用的。
1、框架的缓存设计
在我们的微信开发框架中,缓存作为数据库和对外接口之间的一个分层,提供数据的缓存响应处理,如下结构所示是Web API层对缓存的架构设计。


在缓存的处理中,我侧重于使用CacheManager,这个缓存框架是一个集大成者,关于CacheManager 的介绍,我们可以回顾下我之前的随笔《.NET缓存框架CacheManager在混合式开发框架中的应用(1)-CacheManager的介绍和使用》。
CacheManager是一个以C#语言开发的开源.Net缓存框架抽象层。它不是具体的缓存实现,但它支持多种缓存提供者(如Redis、Memcached等)并提供很多高级特性。
CacheManager 主要的目的使开发者更容易处理各种复杂的缓存场景,使用CacheManager可以实现多层的缓存,让进程内缓存在分布式缓存之前,且仅需几行代码来处理。
CacheManager 不仅仅是一个接口去统一不同缓存提供者的编程模型,它使我们在一个项目里面改变缓存策略变得非常容易,同时也提供更多的特性:如缓存同步、并发更新、序列号、事件处理、性能计算等等,开发人员可以在需要的时候选择这些特性。
CacheManager的GitHub源码地址为:https://github.com/MichaCo/CacheManager,如果需要具体的Demo及说明,可以访问其官网:http://cachemanager.michaco.net
2、在微信框架中整合CacheManager 缓存框架
在使用CacheManager 缓存的时候,我们可以直接使用相关对象进行处理,首先需要定义一个类来进行初始化缓存的设置,然后进行调用,调用的时候可以使用IOC的方式构建对象,如下代码所示创建一个自定义的缓存管理类
/// <summary>
/// 基于CacheManager的接口处理
/// </summary>
public class CacheManager : ICacheManager
{
/// <summary>
/// ICacheManager对象
/// </summary>
public ICacheManager<object> Manager { get; set; } /// <summary>
/// 默认构造函数
/// </summary>
public CacheManager()
{
// 初始化缓存管理器
Manager = CacheFactory.Build("getStartedCache", settings =>
{
settings
.WithSystemRuntimeCacheHandle("handleName")
.And
.WithRedisConfiguration("redis", config =>
{
config.WithAllowAdmin()
.WithDatabase()
.WithEndpoint("localhost", );
})
.WithMaxRetries()
.WithRetryTimeout()
.WithRedisBackplane("redis")
.WithRedisCacheHandle("redis", true)
;
});
}
}
}
然后在Autofac的配置文件中配置缓存的相关信息,如下文件所示。

如果直接使用Autofac的构造类来处理,那么调用缓存处理的代码如下所示。
//通过AutoFac工厂获取对应的接口实现
var cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager>();
if (cache != null)
{
accountInfo = cache.Manager.Get(key) as AccountInfo;
if (accountInfo == null)
{
var value = BLLFactory<Account>.Instance.FindByID(accountId);
var item = new CacheItem<object>(key, value, ExpirationMode.Absolute, TimeSpan.FromMinutes(TimeOut_Minutes));
cache.Manager.Put(item); accountInfo = cache.Manager.Get(key) as AccountInfo;
}
}
如果为了使用方便,我们还可以对这个辅助类进行进一步的封装,以便对它进行统一的调用处理即可。
/// <summary>
/// 基于.NET CacheManager的缓存管理,文档参考:http://cachemanager.michaco.net/documentation
/// </summary>
public class CacheManagerHelper
{
/// <summary>
/// 锁定处理变量
/// </summary>
private static readonly object locker = new object(); /// <summary>
/// 创建一个缓存的键值,并指定响应的时间范围,如果失效,则自动获取对应的值
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="key">对象的键</param>
/// <param name="cachePopulate">获取缓存值的操作</param>
/// <param name="expiration">失效的时间范围</param>
/// <param name="mode">失效类型</param>
/// <returns></returns>
public static T GetCacheItem<T>(string key, Func<T> cachePopulate, TimeSpan expiration,
string region = "_", ExpirationMode mode = ExpirationMode.Sliding) where T :class
{
CacheItem<object> outItem = null;
//通过AutoFac工厂获取对应的接口实现
var cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager>();
if (cache != null)
{
if (cache.Manager.Get(key, region) == null)
{
lock (locker)
{
if (cache.Manager.Get(key, region) == null)
{
//Add、Put差异,Add只有在空值的情况下执行加入并返回true,Put总会替换并返回True
//如果按下面的方式加入,那么会留下历史丢弃的键值: cache.Manager.Put(key, value); var value = cachePopulate();
var item = new CacheItem<object>(key, region, value, mode, expiration);
cache.Manager.Put(item);
}
}
} return cache.Manager.Get(key, region) as T;
}
else
{
throw new ArgumentNullException("AutoFac配置参数错误,请检查autofac.config是否存在ICacheManager的定义");
}
}
}
不过由于官方已经提供了一个类似上面的代码逻辑的TryGetOrAdd方法,这个方法的定义如下所示。
TryGetOrAdd(String, String, Func<String, String, TCacheValue>, out TCacheValue)
Tries to either retrieve an existing item or add the item to the cache if it does not exist. The valueFactory will be evaluated only if the item does not exist.
Declaration
bool TryGetOrAdd(string key, string region, Func<string, string, TCacheValue> valueFactory, out TCacheValue value)
Parameters
| Type | Name | Description |
|---|---|---|
| String | key |
The cache key. |
| String | region |
The cache region. |
| Func<String, String, TCacheValue> | valueFactory |
The method which creates the value which should be added. |
| TCacheValue | value |
The cache value. |
Returns
| Type | Description |
|---|---|
| Boolean |
|
我们根据这个参数的定义,可以进一步简化上面的辅助类代码。
cache.Manager.TryGetOrAdd(key, region, (_key, _region) =>{
var value = cachePopulate();
var item = new CacheItem<object>(key, region, value, mode, expiration);
return item;
}, out outItem);
return outItem as T;
整个类的代码如下所示
/// <summary>
/// 基于.NET CacheManager的缓存管理,文档参考:http://cachemanager.michaco.net/documentation
/// </summary>
public class CacheManagerHelper
{
/// <summary>
/// 创建一个缓存的键值,并指定响应的时间范围,如果失效,则自动获取对应的值
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="key">对象的键</param>
/// <param name="cachePopulate">获取缓存值的操作</param>
/// <param name="expiration">失效的时间范围</param>
/// <param name="mode">失效类型</param>
/// <returns></returns>
public static T GetCacheItem<T>(string key, Func<T> cachePopulate, TimeSpan expiration,
string region = "_", ExpirationMode mode = ExpirationMode.Sliding) where T :class
{
CacheItem<object> outItem = null;
//通过AutoFac工厂获取对应的接口实现
var cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager>();
if (cache != null)
{
cache.Manager.TryGetOrAdd(key, region, (_key, _region) =>{
var value = cachePopulate();
var item = new CacheItem<object>(key, region, value, mode, expiration);
return item;
}, out outItem);
return outItem as T;
}
else
{
throw new ArgumentNullException("AutoFac配置参数错误,请检查autofac.config是否存在ICacheManager的定义");
}
}
}
这样代码就简化了不少,而且不用自己控制读取的线程锁了,下面代码是使用辅助类实现缓存的添加及获取处理。
/// <summary>
/// 为避免频繁的对数据库检索,提高获取账号信息的速度
/// 我们把账号信息根据ID缓存起来,方便快速使用,提高效率。
/// </summary>
public static AccountInfo GetAccountByID(string accountId)
{
AccountInfo accountInfo = null; #region 使用.NET CacheManager缓存
//正常情况下access_token有效期为7200秒,这里使用缓存设置短于这个时间即可
var key = "GetAccountByID_" + accountId;
accountInfo = CacheManagerHelper.GetCacheItem<AccountInfo>(key, () =>
{
return BLLFactory<Account>.Instance.FindByID(accountId);
}, TimeSpan.FromMinutes(TimeOut_Minutes)); return accountInfo;
}
通过这样的辅助类封装,我们可以在需要缓存的函数里面,统一使用辅助类对数据进行缓存或者读取缓存的操作。
我们也可以直接使用Autofac构建的缓存管理进行操作,如在小程序里面,我们对用户敏感数据的解密处理函数,如下所示。
/// <summary>
/// 根据微信小程序平台提供的解密算法解密数据
/// </summary>
[HttpGet]
public SmallAppUserInfo Decrypt(string encryptedData, string iv, string thirdkey)
{
SmallAppUserInfo userInfo = null; //通过AutoFac工厂获取对应的接口实现
var cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager>();
if (cache != null)
{
//从缓存里面,获取对应的SessionKey
var sessionkey = cache.Manager.Get(thirdkey);
if (sessionkey != null)
{
//对用户身份加密数据进行解析,获取包含openid等属性的完整对象
IBasicApi api = new BasicApi();
userInfo = api.Decrypt(encryptedData, iv, sessionkey.ToString());
}
}
return userInfo;
}
C#开发微信门户及应用(48) - 在微信框架中整合CacheManager 缓存框架的更多相关文章
- C#开发微信门户及应用(39)--使用微信JSSDK实现签到的功能
随着微信开逐步开放更多JSSDK的接口,我们可以利用自定义网页的方式来调用更多微信的接口,实现我们更加丰富的界面功能和效果,例如我们可以在页面中调用各种手机的硬件来获取信息,如摄像头拍照,GPS信息. ...
- C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据
我曾经在系列文章中的<C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍>中介绍了微信菜单里面的重定向操作,通过这个重定向操作,我们可以获取一个code值,然后获取用户的open ...
- C#开发微信门户及应用(40)--使用微信JSAPI实现微信支付功能
在我前面的几篇博客,有介绍了微信支付.微信红包.企业付款等各种和支付相关的操作,不过上面都是基于微信普通API的封装,本篇随笔继续微信支付这一主题,继续介绍基于微信网页JSAPI的方式发起的微信支付功 ...
- C#开发微信门户及应用(41)--基于微信开放平台的扫码登录处理
在现今很多网站里面,都使用了微信开放平台的扫码登录认证处理,这样做相当于把身份认证交给较为权威的第三方进行认证,在应用网站里面可以不需要存储用户的密码了.本篇介绍如何基于微信开放平台的扫码进行网站的登 ...
- C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍
最近对微信接口进行深入的研究,通过把底层接口一步步进行封装后,逐步升级到自动化配置.自动化应答,以及后台处理界面的优化和完善上,力求搭建一个较为完善.适用的微信门户应用管理系统. 微信门户应用管理系统 ...
- C#开发微信门户及应用(4)--关注用户列表及详细信息管理
在上个月的对C#开发微信门户及应用做了介绍,写过了几篇的随笔进行分享,由于时间关系,间隔了一段时间没有继续写这个系列的博客了,并不是对这个方面停止了研究,而是继续深入探索这方面的技术,为了更好的应用起 ...
- C#开发微信门户及应用(25)-微信企业号的客户端管理功能
我们知道,微信公众号和企业号都提供了一个官方的Web后台,方便我们对微信账号的配置,以及相关数据的管理功能,对于微信企业号来说,有通讯录中的组织架构管理.标签管理.人员管理.以及消息的发送等功能,其中 ...
- C#开发微信门户及应用(38)--微信摇一摇红包功能
摇一摇周边红包接口是为线下商户提供的发红包功能.用户可以在商家门店等线下场所通过摇一摇周边领取商家发放的红包.我曾经在<C#开发微信门户及应用(28)--微信“摇一摇·周边”功能的使用和接口的实 ...
- C#开发微信门户及应用(37)--微信公众号标签管理功能
微信公众号,仿照企业号的思路,增加了标签管理的功能,对关注的粉丝可以设置标签管理,实现更加方便的分组管理功能.开发者可以使用用户标签管理的相关接口,实现对公众号的标签进行创建.查询.修改.删除等操作, ...
随机推荐
- HTTPCLIENT 模拟登陆
第一步构建忽略https验证的httpclient public static CloseableHttpClient getHttpClient() throws Exception { SSLCo ...
- C#中??和?分别是什么意思?
在C#中??和?分别是什么意思? 1. 可空类型修饰符(?):引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; 是正确的,int i=null ...
- C# 自定义样式实现菜单和工具栏的分割线
在做WinForm界面布局时,菜单和工具栏必不可少!但是MenuStrip和ToolStrip不能够对边框的样式直接设置,如果想实现菜单和工具栏之间的分割线就不容易实现:今天查阅了一下msdn找到了一 ...
- Servlet编程实例2
上次实验中利用HttpServletRespon.sendRedict()方法来实现页面的转跳,而这种重定向请求的方法无法传递缓存的内容. 所以为了做出改进,这次使用RequestDispatcher ...
- OpenTSDB - 分布式可扩展的监控系统
OpenTSDB - A Distributed, Scalable Monitoring System http://opentsdb.net/getting-started.html http:/ ...
- Javaweb学习(一):tomcat服务器配置与启动
目前所使用的集成开发环境为myeclipse10.7,tomcat版本为apache-tomcat-7.0.82,部分编写地方可能有所不同,但是工具不是最主要的,重要的是掌握的知识. tomcat在m ...
- 维多利亚的秘密 golang入坑系统
原文在gitbook,字字原创,版权没有,转载随意. 在写本文的前一天,2017维密在上海开始了. 为了纪念屌丝界的盛世,特为本节起名维多利亚的秘密.现在的社会,要想出名只有抓眼球.所以写份技术文章, ...
- Kaggle初入门
今天成功的进驻kaggle社区了! 所以以后就要跟kaggle上面的各位一起学习啦! 今天十分成功的在tensorflow的环境里面装了一堆库--什么seaborn啊pandas啊都一次过 然后--并 ...
- Vue 浅析与实践
欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:曾柏羲 导语 入职接到的第一个需求是实现一个关于K歌实体售卖的ERP系统,管理系统过去做过不少,这次打算换个姿势,基于时下正热但早已不新 ...
- Less的嵌套规则
Less的嵌套规则 在使用标准CSS时,要为多层嵌套的元素定义样式,要么使用后代选择器从外到内的嵌套定义,要么给这个元素加上类名或 id 来定义.这样的写法虽然很好理解,但维护起来很不方便,因为无法清 ...