• .NET WebAPI 采用 IDistributedCache 实现分布式缓存过滤器 Redis 模式


    分布式缓存是由多个应用服务器共享的缓存,通常作为访问它的应用服务器的外部服务进行维护。 分布式缓存可以提高 ASP.NET Core 应用的性能和可伸缩性,尤其是当应用由云服务或服务器场托管时。

    与其他将缓存数据存储在单个应用服务器上的缓存方案相比,分布式缓存具有多个优势。

    当分发缓存数据时,数据:

    • 在多个服务器的请求之间保持一致(一致性)。
    • 在进行服务器重启和应用部署后仍然有效。
    • 不使用本地内存。

    实现方案采用 Redis 作为缓存的数据托管方案,接口使用微软官方的 IDistributedCache 接口实现。

    首选注入 分布式缓存服务

    复制代码
    //注册缓存服务 Redis模式
    builder.Services.AddStackExchangeRedisCache(options =>
    {
        options.Configuration = builder.Configuration.GetConnectionString("redisConnection");
        options.InstanceName = "cache";
    });
    复制代码

     

    IDistributedCache 的扩展类,后面过滤器操作缓存需要用到这个扩展方法。

    复制代码
    using Microsoft.Extensions.Caching.Distributed;
    
    namespace Common
    {
    
        /// 
        /// 扩展分布式缓存接口,集成常用方法
        /// 
        public static class IDistributedCacheExtension
        {
    
            /// 
            /// 删除指定key
            /// 
            /// 
            /// 
            public static bool Remove(this IDistributedCache distributedCache, string key)
            {
                try
                {
                    distributedCache.Remove(key);
                    return true;
                }
                catch
                {
                    return false;
                }
            }
    
    
            /// 
            /// 设置object类型的key
            /// 
            /// 
            /// 
            /// 
            public static bool SetObject(this IDistributedCache distributedCache, string key, object value)
            {
                try
                {
                    var valueStr = JsonHelper.ObjectToJson(value);
                    distributedCache.SetString(key, valueStr);
                    return true;
                }
                catch
                {
                    return false;
                }
            }
    
    
            /// 
            /// 设置string类型key,包含有效时间
            /// 
            /// 
            /// 
            /// 
            /// 
            public static bool SetString(this IDistributedCache distributedCache, string key, string value, TimeSpan timeOut)
            {
                try
                {
                    distributedCache.SetString(key, value, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = timeOut });
                    return true;
                }
                catch
                {
                    return false;
                }
            }
    
    
            /// 
            /// 设置object类型key,包含有效时间
            /// 
            /// 
            /// 
            /// 
            /// 
            public static bool SetObject(this IDistributedCache distributedCache, string key, object value, TimeSpan timeOut)
            {
                try
                {
                    var valueStr = JsonHelper.ObjectToJson(value);
                    distributedCache.SetString(key, valueStr, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = timeOut });
                    return true;
                }
                catch
                {
                    return false;
                }
            }
    
    /// /// 读取 Object 类型的key /// /// /// /// public static T GetObject(this IDistributedCache distributedCache, string key) { try { var valueStr = distributedCache.GetString(key); var value = JsonHelper.JsonToObject(valueStr); return value; } catch { return default!; } }
    /// /// 判断是否存在指定key /// /// /// public static bool IsContainKey(this IDistributedCache distributedCache, string key) { if (string.IsNullOrEmpty(distributedCache.GetString(key))) { return false; } else { return true; } } } }
    复制代码

     

    WebAPI 的缓存过滤器代码如下:

    复制代码
    using Common;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Filters;
    using Microsoft.Extensions.Caching.Distributed;
    using System.Text.Json;
    
    namespace WebAPI.Filters
    {
    
        /// 
        /// 缓存过滤器
        /// 
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
        public class CacheDataFilter : Attribute, IActionFilter
        {
    
            /// 
            /// 缓存时效有效期,单位 秒
            /// 
            public int TTL { get; set; }
    
    
            /// 
            /// 是否使用 Token
            /// 
            public bool IsUseToken { get; set; }
    
    
            void IActionFilter.OnActionExecuting(ActionExecutingContext context)
            {
                string key = "";
    
                if (IsUseToken)
                {
                    var token = context.HttpContext.Request.Headers.Where(t => t.Key == "Authorization").Select(t => t.Value).FirstOrDefault();
    
                    key = context.ActionDescriptor.DisplayName + "_" + context.HttpContext.Request.QueryString + "_" + token;
                }
                else
                {
                    key = context.ActionDescriptor.DisplayName + "_" + context.HttpContext.Request.QueryString;
                }
    
                key = "CacheData_" + CryptoHelper.GetMD5(key);
    
                try
                {
                    var distributedCache = context.HttpContext.RequestServices.GetRequiredService();
                    var cacheInfo = distributedCache.GetObject<object>(key);
    
                    if (cacheInfo != null)
                    {
                        if (((JsonElement)cacheInfo).ValueKind == JsonValueKind.String)
                        {
                            context.Result = new ObjectResult(cacheInfo.ToString());
                        }
                        else
                        {
                            context.Result = new ObjectResult(cacheInfo);
                        }
                    }
                }
                catch (Exception ex)
                {
                    var logger = context.HttpContext.RequestServices.GetRequiredService>();
                    logger.LogError(ex, "缓存模块异常-In");
                }
            }
    
    
            void IActionFilter.OnActionExecuted(ActionExecutedContext context)
            {
                try
                {
                    if (context.Result is ObjectResult objectResult && objectResult.Value != null)
                    {
                        string key = "";
    
                        if (IsUseToken)
                        {
                            var token = context.HttpContext.Request.Headers.Where(t => t.Key == "Authorization").Select(t => t.Value).FirstOrDefault();
    
                            key = context.ActionDescriptor.DisplayName + "_" + context.HttpContext.Request.QueryString + "_" + token;
                        }
                        else
                        {
                            key = context.ActionDescriptor.DisplayName + "_" + context.HttpContext.Request.QueryString;
                        }
    
                        key = "CacheData_" + CryptoHelper.GetMD5(key);
    
                        if (objectResult.Value != null)
                        {
                            var distributedCache = context.HttpContext.RequestServices.GetRequiredService();
                            distributedCache.SetObject(key, objectResult.Value, TimeSpan.FromSeconds(TTL));
                        }
    
                    }
                }
                catch (Exception ex)
                {
                    var logger = context.HttpContext.RequestServices.GetRequiredService>();
                    logger.LogError(ex, "缓存模块异常-Out");
                }
    
            }
        }
    }
    复制代码

    缓存过滤器的入参只有两个

    • TTL 缓存有效期以秒为单位
    • IsUseToken 是否使用 Token 区分不同的用户身份,之所以加入这个参数,主要是因为有些接口虽然多个用户请求时的入参一样,但是不同的用户需要返回不同的信息,所以面对这种类型的接口需要将 IsUseToken 设定为 True。

    过滤器的使用方法就很简单了,直接附在对应的接口 Action 方法上就可以,如下:

    [CacheDataFilter(TTL = 60, IsUseToken = true)]
    public DtoUser? GetUserInfo()
    {
        ///省略业务逻辑
    }

    此处对于 GetUserInfo  接口添加了缓存过滤器,对数据缓存60秒钟,并且针对 不同的Token身份进行了区分,因为这边的逻辑是通过 Token 识别用户身份的,虽然请求没有特别的参数,但是需要为不同用户的请求返回对应的用户信息,并且分别缓存。

    至此 .NET WebAPI 采用 IDistributedCache 实现分布式缓存过滤器 Redis 模式 就讲解完了,有任何不明白的,可以在文章下面评论或者私信我,欢迎大家积极的讨论交流,有兴趣的朋友可以关注我目前在维护的一个 .NET 基础框架项目,项目地址如下
  • 相关阅读:
    2021 ICPC 昆明 I Mr Main and Windmills(直线与线段的交点)
    Java 多线程:并发编程的三大特性
    计算机网络基础知识
    海马算法 (Sea-Horse optimizer ,SHO)附matlab代码
    19.项目开发之量化交易QuantTrade(一)
    初识ElasticSearch
    280049flash guide中文
    JDBC一般使用过程+两种statement的区别
    毕业季限时“开业”,麓山南便利店送给毕业生满满的仪式感
    VS2022使用体系结构查看类图和根据依赖项产生关系图
  • 原文地址:https://www.cnblogs.com/berkerdong/p/16597795.html