? 优质资源分享 ?
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
? Python实战微信订餐小程序 ? | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
?Python量化交易实战? | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
分布式缓存是由多个应用服务器共享的缓存,通常作为访问它的应用服务器的外部服务进行维护。 分布式缓存可以提高 ASP.NET Core 应用的性能和可伸缩性,尤其是当应用由云服务或服务器场托管时。
与其他将缓存数据存储在单个应用服务器上的缓存方案相比,分布式缓存具有多个优势。
当分发缓存数据时,数据:
- 在多个服务器的请求之间保持一致(一致性)。
- 在进行服务器重启和应用部署后仍然有效。
- 不使用本地内存。
实现方案采用 Redis 作为缓存的数据托管方案,接口使用微软官方的 IDistributedCache 接口实现。
首选安装 Microsoft.Extensions.Caching.StackExchangeRedis 组件包
然后注入 分布式缓存服务
//注册缓存服务 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 基础框架项目,项目地址如下
https://github.com/berkerdong/NetEngine.git
https://gitee.com/berkerdong/NetEngine.git
转载请注明:xuhss » .NET WebAPI 采用 IDistributedCache 实现分布式缓存过滤器 Redis 模式