Cuture.AspNetCore.ResponseCaching
2.2.0
dotnet add package Cuture.AspNetCore.ResponseCaching --version 2.2.0
NuGet\Install-Package Cuture.AspNetCore.ResponseCaching -Version 2.2.0
<PackageReference Include="Cuture.AspNetCore.ResponseCaching" Version="2.2.0" />
paket add Cuture.AspNetCore.ResponseCaching --version 2.2.0
#r "nuget: Cuture.AspNetCore.ResponseCaching, 2.2.0"
// Install Cuture.AspNetCore.ResponseCaching as a Cake Addin #addin nuget:?package=Cuture.AspNetCore.ResponseCaching&version=2.2.0 // Install Cuture.AspNetCore.ResponseCaching as a Cake Tool #tool nuget:?package=Cuture.AspNetCore.ResponseCaching&version=2.2.0
Cuture.AspNetCore.ResponseCaching
1. Intro
The asp.net core
server-side caching component implemented based on ResourceFilter
and ActionFilter
;
基于ResourceFilter
和ActionFilter
实现的asp.net core
服务端缓存组件
2. 注意项
- 针对
Action
的缓存实现,基于Filter
,非中间件/AOP实现; - 命中缓存时直接将内容写入响应流,省略了序列化、反序列化等操作;
- 只会缓存响应内容和
ContentType
,忽略了其它响应Header; - 支持基于
QueryKey
、FormKey
、Header
、Claim
、Model
中单个或多个组合的缓存键生成; - 已实现基于
Memory
和Redis
(StackExchange.Redis)的缓存,可拓展; - 默认缓存Key生成器会包含请求路径为缓存Key;
- 默认缓存Key是大小写不敏感(强制转换为小写)的;
Asp.net Core
版本要求 -6.0
以上;Diagnostics
支持;- 执行流程概览;
3. 如何使用
3.1 安装Nuget
包
Install-Package Cuture.AspNetCore.ResponseCaching
3.2 在Startup
中配置选项
public void ConfigureServices(IServiceCollection services)
{
//....Other Settings
services.AddCaching(options =>
{
options.Enable = true; //是否启用响应缓存
options.DefaultCacheStoreLocation = CacheStoreLocation.Memory; //默认缓存数据存储位置 - Memory
options.DefaultExecutingLockMode = ExecutingLockMode.None; //默认执行锁定模式 - 不锁定
options.DefaultStrictMode = CacheKeyStrictMode.Ignore; //默认缓存Key的严格模式 - 忽略没有的找到的Key
options.LockedExecutionLocalResultCache = new MemoryCache(new MemoryCacheOptions()); //锁定执行时,响应的本地缓存
options.MaxCacheableResponseLength = 1024 * 1024; //默认最大可缓存的响应内容长度
options.MaxCacheKeyLength = 1024; //最大缓存Key长度
options.OnCannotExecutionThroughLock = (cacheKey, filterContext, next) => Task.CompletedTask; //无法使用锁执行请求时(Semaphore池用尽)的回调
options.OnExecutionLockTimeoutFallback = (cacheKey, filterContext, next) => Task.CompletedTask; //执行锁定超时后的处理委托
});
//以下为可选配置
// 锁定执行的相关配置
services.PostConfigure<ResponseCachingExecutingLockOptions>(options =>
{
options.MinimumSemaphoreRetained = 50; //信号池的最小保留大小
options.MaximumSemaphorePooled = 1000; //信号池的最大大小
options.MinimumExecutingLockRetained = 50; //执行锁池的最小保留大小
options.MaximumExecutingLockPooled = 1000; //执行锁池的最大大小
options.SemaphoreRecycleInterval = TimeSpan.FromMinutes(4); //信号池的回收间隔
options.ExecutingLockRecycleInterval = TimeSpan.FromMinutes(2); //执行锁池的回收间隔
});
}
3.3 为Action
方法标记ResponseCachingMetadata
Attribute与ResponseCacheable
Attribute
3.3.1 工作方式概述
ResponseCachingMetadata
为派生自IResponseCachingMetadata
的Attribute
,用于描述响应缓存的配置等细节;ResponseCacheable
为内部实现的Attribute,用于使用Endpoint
获取对应Action
的ResponseCachingMetadata
并动态构建Filter
;
IResponseCachingMetadata
接口及内置的ResponseCachingMetadata
列表:
| 接口 | 描述内容 | 内置实现 |
| --- | --- | --- |
|IResponseClaimCachePatternMetadata
|创建缓存时依据的 Claim 类型|ResponseCachingAttribute
|
|IResponseFormCachePatternMetadata
|创建缓存时依据的 Form 键|ResponseCachingAttribute
|
|IResponseHeaderCachePatternMetadata
|创建缓存时依据的 Header 键|ResponseCachingAttribute
|
|IResponseModelCachePatternMetadata
|创建缓存时依据的 Model 参数名|ResponseCachingAttribute
|
|IResponseQueryCachePatternMetadata
|创建缓存时依据的 Query 键|ResponseCachingAttribute
|
|ICacheKeyGeneratorMetadata
|用于生成缓存Key的ICacheKeyGenerator
实现类型|CacheKeyGeneratorAttribute
|
|ICacheKeyStrictModeMetadata
|缓存键严格模式|ResponseCachingAttribute
|
|ICacheModelKeyParserMetadata
|用于生成Model的缓存Key的IModelKeyParser
实现类型|CacheModelKeyParserAttribute
|
|ICacheModeMetadata
|缓存模式|ResponseCachingAttribute
|
|ICacheStoreLocationMetadata
|缓存数据存储位置|ResponseCachingAttribute
|
|IDumpStreamInitialCapacityMetadata
|Dump响应的Stream初始容量|ResponseDumpCapacityAttribute
|
|IExecutingLockMetadata
|Action
的执行锁定方式|ExecutingLockAttribute
|
|IHotDataCacheMetadata
|热点数据缓存方式|HotDataCacheAttribute
|
|IMaxCacheableResponseLengthMetadata
|最大可缓存响应长度|ResponseCachingAttribute
|
|IResponseDurationMetadata
|缓存时长|ResponseCachingAttribute
|
3.3.2 使用内置的特性
使用[ResponseCaching]
标记需要缓存响应的Action
,或者使用简便标记[CacheByQuery]
、[CacheByForm]
、[CacheByHeader]
、[CacheByClaim]
、[CacheByModel]
、[CacheByPath]
、[CacheByFullUrl]
(这些标记都是继承自ResponseCaching
并进行了简单的预设置);
[ResponseCaching(
60, //缓存时长(秒)
Mode = CacheMode.Custom, //设置缓存模式 - 自定义缓存Key生成
VaryByClaims = new[] { "id" }, //依据Claim中的`id`进行构建缓存Key
VaryByHeaders = new[] { "version" }, //依据Header中的`version`进行构建缓存Key
VaryByQueryKeys = new[] { "page", "pageSize" }, //依据Query中的`page`和`pageSize`进行构建缓存Key
VaryByModels = new[] { "input" }, //依据Model中的`input`进行构建缓存Key
StoreLocation = CacheStoreLocation.Memory, //设置缓存数据存储位置 - Memory
StrictMode = CacheKeyStrictMode.Ignore, //缓存Key的严格模式 - 忽略没有的找到的Key
MaxCacheableResponseLength = 1024 * 1024 //最大可缓存的响应内容长度
)]
[CacheKeyGenerator(typeof(CustomCacheKeyGenerator), FilterType.Resource)] //使用 CustomCacheKeyGenerator 作为缓存key生成器
[CacheModelKeyParser(typeof(CustomModelKeyParser))] //使用 CustomModelKeyParser 作为model的key解析器
[ExecutingLock(ExecutingLockMode.CacheKeySingle)] //执行action时锁定执行过程,锁定粒度为每个缓存Key,不允许并行执行
[HotDataCache(50, HotDataCachePolicy.LRU)] //将热点数据缓存在内存中,淘汰算法为LRU
[ResponseDumpCapacity(1024 * 1024)] //指定dump响应的stream初始化容量,减少不必要的扩容
public IEnumerable<DataDto> Foo([FromQuery] int page, [FromQuery] int pageSize, [FromBody] RequestDto input)
{
//...action logic
}
3.3.3 使用自定义特性
- 自定义
Attribue
,继承继承ResponseCacheableAttribute
(或继承IFilterFactory
自行实现构建逻辑); - 自定义
Attribue
,继承需要设置的IResponseCachingMetadata
接口; - 使用上述自定义特性标记需要缓存的
Action
方法;
- 可以使用多个
Attribute
分别实现IResponseCachingMetadata
,也可以将所有的功能在一个Attribute
实现;
3.4 使用Redis
进行缓存
不配置时将默认使用MemoryCache
进行缓存
3.4.1 安装Nuget
包
Install-Package Cuture.AspNetCore.ResponseCaching.StackExchange.Redis
3.4.2 配置Redis缓存
public void ConfigureServices(IServiceCollection services)
{
//....Other Settings
services.AddCaching()
.UseRedisResponseCache("redis:6379", //redis配置字符串
"ResponseCache_" //缓存前缀
);
}
3.5 拦截器
- 当前只有两个拦截器
- 缓存存储拦截器:
ICacheStoringInterceptor
- 缓存写入拦截器:
IResponseWritingInterceptor
- 缓存存储拦截器:
- 拦截器可以有多个;
- 拦截器执行顺序为
全局Service拦截器
→全局Instance拦截器
→Attribute拦截器
;
3.5.1 自定义拦截器
- 继承需要拦截的流程接口即可;
public class IgnoreHelloCacheStoringInterceptor
: Attribute //继承Attribute,以进行单个Action的设置
, ICacheStoringInterceptor //响应存储拦截器
{
public async Task<ResponseCacheEntry?> OnCacheStoringAsync(ActionContext actionContext, string key, ResponseCacheEntry entry, OnCacheStoringDelegate<ActionContext> next)
{
if (key == "hello")
{
return null; //key为hello时,不进行存储,且不进行后续的处理
}
return await next(actionContext, key, entry); //执行后续处理
}
}
3.5.2 设置全局拦截器
- 全局生效的拦截器
public void ConfigureServices(IServiceCollection services)
{
//....Other Settings
services.AddCaching().ConfigureInterceptor(options =>
{
//Instance拦截器
options.AddInterceptor(new CacheHitStampInterceptor("key", "value")); //添加拦截器 CacheHitStampInterceptor 的实例作为全局拦截器
//Service拦截器
options.AddServiceInterceptor<CustomInterceptor>(); //从DI中获取 CustomInterceptor 作为全局拦截器
});
}
3.5.2 设置Action
拦截器
- 将拦截器
Attribute
设置到对应的Action
方法即可,此时拦截器只针对当前Action
生效
3.5.3 内置的CacheHitStamp
缓存处理拦截器
- 此拦截器将会在命中缓存时向响应的
HttpHeader
中添加指定内容 - 此设置可能因为前置拦截器短路而不执行
配置方法:
public void ConfigureServices(IServiceCollection services)
{
//....Other Settings
services.AddCaching().UseCacheHitStampHeader("cached", "1"); //当命中缓存时,响应的Header中将附加`cached: 1`
}
4. 示例
4.1 基于Query缓存
使用query中的page和pageSize缓存
[HttpGet]
[CacheByQuery(60, "page", "pageSize")]
public ResultDto Foo(int page, int pageSize)
{
//...action logic
}
4.2 基于Form缓存
使用form中的page和pageSize缓存
[HttpGet]
[CacheByForm(60, "page", "pageSize")]
public ResultDto Foo()
{
int page = int.Parse(Request.Form["page"]);
int pageSize = int.Parse(Request.Form["pageSize"]);
//...action logic
}
4.3 基于Model缓存
使用action的参数进行缓存
[HttpPost]
[CacheByModel(60)]
public ResultDto Foo(RequestDto input)
{
//...action logic
}
public class RequestDto : ICacheKeyable
{
public int Page { get; set; }
public int PageSize { get; set; }
public string AsCacheKey() => $"{Page}_{PageSize}";
}
使用Model缓存会使用以下方式的其中一种生成Key(优先级从上往下)
- 指定
ModelKeyParserType
- Model类实现
ICacheKeyable
接口 - Model类的
ToString
方法
此时Filter
由ResourceFilter
转变为ActionFilter
4.4 基于用户缓存
使用用户凭据中的id
和query中的page
与pageSize
组合构建缓存Key
[ResponseCaching(60,
Mode = CacheMode.Custom,
VaryByClaims = new[] { "id" },
VaryByQueryKeys = new[] { "page", "pageSize" })]
public ResultDto Foo(int page, int pageSize)
{
//...action logic
}
5. 自定义缓存实现
实现IMemoryResponseCache
或IDistributedResponseCache
接口;并将实现注入asp.net core
的DI,替换掉默认实现;
Diagnostics支持
- 部分功能已使用
Diagnostic
,DiagnosticName
为Cuture.AspNetCore.ResponseCaching
;
事件列表如下:
事件名称 | 事件 |
---|---|
Cuture.AspNetCore.ResponseCaching.StartProcessingCache | 开始处理缓存 |
Cuture.AspNetCore.ResponseCaching.EndProcessingCache | 处理缓存结束 |
Cuture.AspNetCore.ResponseCaching.CacheKeyGenerated | 缓存key已生成 |
Cuture.AspNetCore.ResponseCaching.ResponseFromCache | 从缓存响应请求 |
Cuture.AspNetCore.ResponseCaching.ResponseFromActionResult | 使用IActionResult 响应请求事件 |
Cuture.AspNetCore.ResponseCaching.CacheKeyTooLong | 缓存键过长 |
Cuture.AspNetCore.ResponseCaching.NoCachingFounded | 没有找到缓存 |
Cuture.AspNetCore.ResponseCaching.CacheBodyTooLong | 缓存内容过大 |
使用ILogger
打印事件信息
- 已实现简单的
Diagnostic
订阅并打印,直接启用即可输出日志; - 使用
Diagnostic
会对性能有那么一点影响;
1. 配置服务时添加Logger
services.AddCaching()
.AddDiagnosticDebugLogger() //在Debug模式下使用Logger输出Diagnostic事件信息
.AddDiagnosticReleaseLogger(); //在Release模式下使用Logger输出Diagnostic事件信息
2. 构建应用时启用Logger
app.EnableResponseCachingDiagnosticLogger();
如上配置后,内部将订阅相关Diagnostic
,并将事件信息使用ILogger
输出。
其它
1. 启用 CacheKeyAccessor
在代码中访问当前请求的 cache key
services.AddCaching()
.EnableCacheKeyAccessor(); //启用 CacheKeyAccessor ,从DI中获取 ICacheKeyAccessor 以访问当前请求的 `cache key`
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- No dependencies.
-
net7.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Cuture.AspNetCore.ResponseCaching:
Package | Downloads |
---|---|
Cuture.AspNetCore.ResponseCaching.StackExchange.Redis
The `asp.net core` server-side caching component implemented based on `ResourceFilter` and `ActionFilter`; 基于`ResourceFilter`和`ActionFilter`实现的`asp.net core`服务端缓存组件。此包为使用 StackExchange.Redis 的 ResponseCache 实现。 |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.2.0 | 22,745 | 3/21/2024 |
2.1.0 | 8,865 | 11/15/2023 |
2.0.2 | 17,688 | 5/13/2023 |
2.0.2-beta-05 | 1,071 | 5/3/2023 |
2.0.2-beta-03 | 232 | 5/2/2023 |
2.0.2-beta-02 | 459 | 4/27/2023 |
2.0.1 | 2,565 | 3/26/2023 |
2.0.0 | 31,993 | 11/13/2021 |
2.0.0-preview-01 | 3,418 | 9/29/2021 |
1.4.1 | 7,593 | 7/1/2021 |
1.4.0 | 8,085 | 4/13/2021 |
1.3.0 | 2,729 | 3/19/2021 |
1.2.0 | 5,458 | 1/25/2021 |
1.1.0 | 3,452 | 12/26/2020 |
1.0.4 | 647 | 11/21/2020 |
1.0.3 | 541 | 11/17/2020 |
1.0.2 | 539 | 11/12/2020 |
1.0.1 | 604 | 9/18/2020 |
1.0.0 | 638 | 9/7/2020 |
0.0.1-alpha0005 | 371 | 8/27/2020 |
0.0.1-alpha0004 | 385 | 8/24/2020 |
0.0.1-alpha0003 | 407 | 8/20/2020 |
0.0.1-alpha0002 | 353 | 8/18/2020 |
0.0.1-alpha0001 | 372 | 8/17/2020 |