using System.Collections.Concurrent;
namespace Dpz.Core.Service;
[Obsolete("请使用 Dpz.Core.SourceGenerator.Attributes.CacheAttribute 配合源生成缓存装饰器。")]
public abstract class AbstractCacheService(IFusionCache fusionCache) : ICacheService
{
private static readonly ConcurrentDictionary<Type, string> PrefixKeyCacheSets = new();
protected virtual string CachePrefixKey =>
PrefixKeyCacheSets.GetOrAdd(
GetType(),
type =>
type.FullName
?? throw new InvalidOperationException(
$"The type {GetType().Name} does not have a FullName."
)
);
protected abstract TimeSpan CacheDefaultExpiration { get; }
public virtual string BuildCacheKey(string method, object? parameters = null) =>
GenerateCacheKey.Build(CachePrefixKey, method, parameters);
public virtual async Task<T> GetOrSetCacheAsync<T>(
string methodName,
Func<FusionCacheFactoryExecutionContext<T>, CancellationToken, Task<T>> factory,
object? parameters = null,
Action<FusionCacheEntryOptions>? setupAction = null,
CancellationToken cancellationToken = default
)
{
var cacheKey = BuildCacheKey(methodName, parameters);
return await fusionCache.GetOrSetAsync<T>(
cacheKey,
async (context, factoryCancellationToken) =>
{
context.Tags = [CachePrefixKey, CachePrefixKey + methodName];
return await factory(context, factoryCancellationToken);
},
setupAction ?? (options => options.SetDuration(CacheDefaultExpiration)),
token: cancellationToken
);
}
public virtual async ValueTask<MaybeValue<T>> TryGetFromCacheAsync<T>(
string methodName,
object? parameters = null,
CancellationToken cancellationToken = default
)
{
var cacheKey = BuildCacheKey(methodName, parameters);
return await fusionCache.TryGetAsync<T>(cacheKey, token: cancellationToken);
}
public virtual async Task SetCacheAsync<T>(
string methodName,
T value,
object? parameters = null,
CancellationToken cancellationToken = default,
params string[] additionalTags
)
{
var cacheKey = BuildCacheKey(methodName, parameters);
var tags = new List<string> { CachePrefixKey, CachePrefixKey + methodName };
tags.AddRange(additionalTags);
await fusionCache.SetAsync(
cacheKey,
value,
options => options.SetDuration(CacheDefaultExpiration),
tags.ToArray(),
token: cancellationToken
);
}
public virtual async Task RemoveCacheAsync(
string methodName,
object? parameters = null,
CancellationToken cancellationToken = default
)
{
var cacheKey = BuildCacheKey(methodName, parameters);
await fusionCache.RemoveAsync(cacheKey, token: cancellationToken);
}
public virtual async Task<IPagedList<T>> GetOrSetPagedListAsync<T>(
string methodName,
Func<List<string>, CancellationToken, Task<IPagedList<T>>> factory,
object? parameters = null,
Action<FusionCacheEntryOptions>? setupAction = null,
CancellationToken cancellationToken = default,
params string[] additionalTags
)
{
var cacheKey = BuildCacheKey(methodName, parameters);
var cache = await fusionCache.TryGetAsync<PagedListWarp<T>>(
cacheKey,
token: cancellationToken
);
if (cache.HasValue)
{
return cache.Value.ToPagedList();
}
var tags = new List<string> { CachePrefixKey, CachePrefixKey + methodName };
if (additionalTags.Length > 0)
{
tags.AddRange(additionalTags);
}
var pagedList = await factory(tags, cancellationToken);
await fusionCache.SetAsync(
cacheKey,
pagedList.ToPagedListWarp(),
setupAction ?? (options => options.SetDuration(CacheDefaultExpiration)),
tags,
token: cancellationToken
);
return pagedList;
}
public virtual ValueTask RemoveByMethodAsync(
string methodName,
CancellationToken cancellationToken = default
)
{
return fusionCache.RemoveByTagAsync(CachePrefixKey + methodName, token: cancellationToken);
}
protected virtual ValueTask OnRemoveByPrefixBeforeAsync(
CancellationToken cancellationToken = default
)
{
return ValueTask.CompletedTask;
}
protected virtual ValueTask OnRemoveByPrefixAfterAsync(
CancellationToken cancellationToken = default
)
{
return ValueTask.CompletedTask;
}
public async ValueTask RemoveByPrefixAsync(CancellationToken cancellationToken = default)
{
await OnRemoveByPrefixBeforeAsync(cancellationToken);
await fusionCache.RemoveByTagAsync(CachePrefixKey, token: cancellationToken);
await OnRemoveByPrefixAfterAsync(cancellationToken);
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码解释
这是一个抽象缓存服务基类,用于提供基于 FusionCache 的缓存功能封装。该类已被标记为过时(Obsolete),建议使用源生成器方式实现缓存装饰器。
主要组成部分
1. 类定义与依赖注入
public abstract class AbstractCacheService(IFusionCache fusionCache) : ICacheService
- 使用主构造函数语法注入
IFusionCache依赖 - 实现
ICacheService接口 - 抽象类,需要子类继承并实现抽象成员
2. 缓存键前缀管理
private static readonly ConcurrentDictionary<Type, string> PrefixKeyCacheSets
protected virtual string CachePrefixKey
- 使用静态并发字典缓存类型的全名作为缓存键前缀
- 每个服务类型对应唯一的前缀,基于类的
FullName - 防止不同服务的缓存键冲突
3. 核心方法
BuildCacheKey - 构建缓存键
根据方法名和参数生成唯一缓存键
GetOrSetCacheAsync - 获取或设置缓存
public virtual async Task<T> GetOrSetCacheAsync<T>(...)
- 如果缓存存在则返回,否则执行工厂方法并缓存结果
- 自动设置缓存标签(Tag):类前缀和方法前缀
- 支持自定义过期时间配置
TryGetFromCacheAsync - 尝试获取缓存
返回 MaybeValue<T> 类型,表示可能存在的值
SetCacheAsync - 设置缓存
- 手动设置缓存值
- 支持附加自定义标签
RemoveCacheAsync - 删除指定缓存
根据方法名和参数删除特定缓存项
GetOrSetPagedListAsync - 分页列表缓存
public virtual async Task<IPagedList<T>> GetOrSetPagedListAsync<T>(...)
- 专门处理分页数据的缓存
- 使用
PagedListWarp<T>包装类进行序列化 - 先尝试获取缓存,不存在则执行工厂方法
RemoveByMethodAsync - 按方法删除
删除特定方法相关的所有缓存(基于标签)
RemoveByPrefixAsync - 按前缀删除
public async ValueTask RemoveByPrefixAsync(...)
- 删除当前服务所有缓存
- 提供前后钩子方法
OnRemoveByPrefixBeforeAsync和OnRemoveByPrefixAfterAsync
设计特点
- 标签系统:使用双层标签(类级别+方法级别)方便批量清除缓存
- 类型安全:使用泛型确保缓存数据类型安全
- 扩展性:虚方法允许子类重写行为
- 抽象配置:子类必须实现
CacheDefaultExpiration定义默认过期时间 - 并发安全:使用
ConcurrentDictionary确保多线程安全
使用场景
适合作为服务层的基类,为数据访问提供统一的缓存能力,减少重复的缓存代码编写。
AI 正在分析代码…
评论加载中...