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(0)
                        .WithEndpoint("localhost", 6379);
                })
                .WithMaxRetries(100)
                .WithRetryTimeout(50)
                .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<StringString, TCacheValue> valueFactory

The method which creates the value which should be added.

TCacheValue value

The cache value.

Returns
Type Description
Boolean

True if the operation succeeds, False in case there are too many retries or the valueFactory returns 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;

整个类的代码如下所示

    /// <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 缓存框架,如需转载请自行联系原博主。



目录
相关文章
|
6月前
|
XML 测试技术 API
利用C#开发ONVIF客户端和集成RTSP播放功能
利用C#开发ONVIF客户端和集成RTSP播放功能
3562 123
|
存储 缓存 NoSQL
缓存加速新玩法,让你的应用飞起来
本文主要叙述如何运用云数据库 Tair 构建缓存,助力应用提速、优化性能。
|
物联网 数据处理 C#
C#实现上位机开发,串口通信,读写串口数据并处理16进制数据
C#实现上位机开发,串口通信,读写串口数据并处理16进制数据。在自动化、物联网以及工业控制行业中,上位机开发是一项重要的技能。本教程主要介绍使用C#进行上位机开发,重点在于串口通信和数据处理。
2537 82
|
10月前
|
存储 监控 算法
基于 C# 时间轮算法的控制局域网上网时间与实践应用
在数字化办公与教育环境中,局域网作为内部网络通信的核心基础设施,其精细化管理水平直接影响网络资源的合理配置与使用效能。对局域网用户上网时间的有效管控,已成为企业、教育机构等组织的重要管理需求。这一需求不仅旨在提升员工工作效率、规范学生网络使用行为,更是优化网络带宽资源分配的关键举措。时间轮算法作为一种经典的定时任务管理机制,在局域网用户上网时间管控场景中展现出显著的技术优势。本文将系统阐述时间轮算法的核心原理,并基于 C# 编程语言提供具体实现方案,以期深入剖析该算法在局域网管理中的应用逻辑与实践价值。
247 5
|
缓存 NoSQL Java
Redis应用—8.相关的缓存框架
本文介绍了Ehcache和Guava Cache两个缓存框架及其使用方法,以及如何自定义缓存。主要内容包括:Ehcache缓存框架、Guava Cache缓存框架、自定义缓存。总结:Ehcache适合用作本地缓存或与Redis结合使用,Guava Cache则提供了更灵活的缓存管理和更高的并发性能。自定义缓存可以根据具体需求选择不同的数据结构和引用类型来实现特定的缓存策略。
803 16
Redis应用—8.相关的缓存框架
|
11月前
|
SQL 小程序 API
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
450 0
|
12月前
|
缓存 NoSQL PHP
用装饰器模式实现多层缓存:让PHP应用更快更稳
通过装饰器模式实现PHP多层缓存架构,详解如何利用内存、Redis、文件缓存组合提升应用性能。包含设计思路、代码示例与实战效果对比,助您构建高效缓存策略。
|
缓存 算法 安全
精选10款C#/.NET开发必备类库(含使用教程),工作效率提升利器!
精选10款C#/.NET开发必备类库(含使用教程),工作效率提升利器!
580 12
|
存储 缓存 小程序
微信小程序数据缓存与本地存储:优化用户体验
本文深入探讨微信小程序的数据缓存与本地存储,介绍其意义、机制及应用场景。通过合理使用内存和本地缓存,可减少网络请求、提升加载速度和用户体验。文中详细讲解了常用缓存API的使用方法,并通过一个新闻列表案例展示了缓存的实际应用。最后提醒开发者注意缓存大小限制、时效性和清理,以确保最佳性能。
|
缓存 API C#
C# 一分钟浅谈:GraphQL 中的缓存策略
本文介绍了在现代 Web 应用中,随着数据复杂度的增加,GraphQL 作为一种更灵活的数据查询语言的重要性,以及如何通过缓存策略优化其性能。文章详细探讨了客户端缓存、网络层缓存和服务器端缓存的实现方法,并提供了 C# 示例代码,帮助开发者理解和应用这些技术。同时,文中还讨论了缓存设计中的常见问题及解决方案,如缓存键设计、缓存失效策略等,旨在提升应用的响应速度和稳定性。
224 13