其实这些微软docs都有现成的,但是现在的人想对浮躁些,去看的不会太多,所以这里就再记录下 ,大家一起懒一起浮躁,呵呵.
0.基础知识
内存中缓存可以存储任何对象;分布式缓存接口仅限于byte[]。
这里只说有这么几种方式,但是不去深入.不喜拉到.
1.常见缓存响应的四种方式
1.1.内存缓存
顾名思义,缓存在内存中,生命周期默认伴随应用程序
1.2.响应缓存
响应缓存控制标头,指定要如何客户端、 代理和响应缓存中间件。
1.3.响应缓存中间件
Microsoft.AspNetCore.ResponseCaching 包中的ResponseCaching
1.4.分布式缓存
就是你对象,她会霸道的和你说和别人说,你是他的....但是到最后到底谁会不是是谁的谁 谁也不知道,但是她有对你的使用权,逛街包要挂在你身上,取东西要从你身上的包里拿出来.
其中的1-3点都是对core本身开刀的手术,4点是不仅对自己动刀子,还要对别人家(服务)动刀子...嗯,比较坏.
1.1内存缓存
内存缓存即我们常用的CacheExtensions 方法 .
对象 : IMemoryCache
可选配置项: MemoryCacheEntryOptions
-
-
- 这是条目可以被缓存的最长时间,防止可调过期持续更新时该条目过时太多。
- 访问此缓存项的请求将重置可调过期时钟。
- 缓存优先级设置为
CacheItemPriority.NeverRemove。 - 在代码中运行该回调的线程不同于从缓存中移除条目的线程。
-
在core中我们使用内存缓存只需要注入 IMemoryCache 即可,然后就是一股脑地 get,getString, set....一顿操作猛如虎;具体案例见官方提供的参考.
1.2响应缓存
a) 使用中间件时,这将为您提供更好地控制负载在服务器上的机会。
方法级属性重写在类级别特性中指定的设置。
1.3响应缓存中间件
引用Microsoft.AspNetCore.App 元包或添加到的包引用Microsoft.AspNetCore.ResponseCaching包。
配置:
在Startup.ConfigureServices,将中间件添加到服务集合。
services.AddResponseCaching();
Microsoft.Net.Http.Headers命名空间。
在startUp.cs的 Configure中
app.UseResponseCaching();
app.Use(async (context, next) => {
// For GetTypedHeaders, add: using Microsoft.AspNetCore.Http;
context.Response.GetTypedHeaders().CacheControl = new Microsoft.Net.Http.Headers.CacheControlHeaderValue() {Public = true, MaxAge = TimeSpan.FromSeconds(10) };
context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] = new string[] { "Accept-Encoding" };
await next();
});
app.UseMvc();
选项:
中间件提供了三个选项用于控制响应缓存。
| 选项 | 描述 |
|---|---|
| UseCaseSensitivePaths | 默认值为 false。 |
| MaximumBodySize | 默认值是64 * 1024 * 1024(64 MB)。 |
| 大小限制 | 默认值是100 * 1024 * 1024(100 MB)。 |
下面的示例配置到中间件:
-
- 小于或等于 1024 字节的缓存响应。
- 将响应存储通过区分大小写的路径 (例如,
/page1和/Page1单独存储)。
services.AddResponseCaching(options =>
{
options.UseCaseSensitivePaths = true;
options.MaximumBodySize = 1024;
});
VaryByQueryKeys:
ResponseCache 属性。
使用ResponseCachingFeature直接从IFeatureCollection的HttpContext:
var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();if (responseCachingFeature != null){ responseCachingFeature.VaryByQueryKeys = new[] { "MyKey" };
}
使用单个值等于*在VaryByQueryKeys随缓存所有请求查询参数而都变化。
响应缓存中间件所使用的 HTTP 标头
用 HTTP 标头配置中间件的响应缓存。
1.4分布式缓存
上面的不是什么重点,小项目用用玩不是问题,所以没太大意思,重点是这里的分布式缓存实现.
分布式的缓存可以提高性能和可伸缩性的 ASP.NET Core 应用,尤其是当应用程序托管的云服务或服务器场。
分布式的缓存具有几大优势,其中缓存的数据存储在单个应用程序服务器其他缓存方案。
当分布式缓存的数据,则数据:
- 是连贯(一致) 跨多个服务器的请求。
- 服务器重新启动和应用部署仍然有效。
- 不使用本地内存。
IDistributedCache接口。
系统必备
Microsoft.Extensions.Caching.SqlServer包。
Redis 包不包括在Microsoft.AspNetCore.App包,因此您必须在项目文件中分别引用 Redis 包。
IDistributedCache 接口
IDistributedCache接口提供了以下方法操作的分布式的缓存实现中的项:
- GetAsync –接受字符串键和检索缓存的项作为
byte[]数组如果在缓存中找到。 - SetAsync –中添加项 (作为
byte[]数组) 到使用字符串键的缓存。 - RefreshAsync –刷新缓存基于其密钥,重置其滑动到期超时值 (如果有) 中的项。
- RemoveAsync –移除缓存项根据其字符串键值。
建立分布式缓存服务
本主题中所述的框架提供实现包括:
分布式的内存缓存
缓存的项存储在运行该应用程序的服务器上的应用程序实例。
分布式内存缓存是一个有用的实现:
- 在开发和测试方案。
- 它允许实现真正的分布式缓存解决方案在将来如果多个节点或容错能力变得非常必要。
示例应用将在开发环境中运行应用时使用的分布式内存缓存:
public void ConfigureServices(IServiceCollection services)
{
if (_hostContext.IsDevelopment()){ services.AddDistributedMemoryCache();}
else
{
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = _config["DistCache_ConnectionString"];
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
}
}
}
1.4.1.分布式的 SQL 服务器缓存
提供 SQL Server 实例 (Data Source),数据库 (Initial Catalog),架构 (例如, dbo),以及表名 (例如, TestCache):
dotnet sql-cache create "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache
记录一条消息以指示该工具已成功:
Table and index were created successfully. 创建的表sql-cache工具具有以下架构:
备注
SqlServerCache。
SqlServerCache非开发环境中:
public void ConfigureServices(IServiceCollection services)
{
if (_hostContext.IsDevelopment())
{
services.AddDistributedMemoryCache();
}
else
{
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString =
_config["DistCache_ConnectionString"];
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
}
备注
连接字符串可能包含应从源代码管理系统的凭据。
1.4.2.分布式的 Redis 缓存
AddDistributedRedisCache):
services.AddDistributedRedisCache(options =>
{
options.Configuration = "localhost";
options.InstanceName = "SampleInstance";
});
若要在本地计算机上安装 Redis:
- Chocolatey Redis 包。
- 运行
redis-server从命令提示符。
使用分布式的缓存
Web 主机: IApplicationLifetime 接口):
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime, IDistributedCache cache)
{
lifetime.ApplicationStarted.Register(() =>
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
cache.Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});
示例应用程序注入IDistributedCache到IndexModel以供索引页。
如果自上一次访问缓存的时间 (已加载此页的最后一个时间) 已过去 20 秒,该页将显示缓存时间已过。
按钮触发器OnPostResetCachedTime处理程序方法。
public class IndexModel : PageModel
{
private readonly IDistributedCache _cache;
public IndexModel(IDistributedCache cache)
{
_cache = cache;
}
public string CachedTimeUTC { get; set; }
public async Task OnGetAsync()
{
CachedTimeUTC = "Cached Time Expired";
var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");
if (encodedCachedTimeUTC != null)
{
CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
}
}
public async Task<IActionResult> OnPostResetCachedTime()
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);
return RedirectToPage();
}
}
备注
无需为IDistributedCache实例使用 Singleton 或 Scoped 生命周期(至少对内置实现来说是这样的)。
显式依赖关系原则。
建议
确定哪一种实现的时IDistributedCache最适合于您的应用程序,请考虑以下:
- 现有的基础结构
- 性能要求
- 成本
- 团队体验
我们建议使用专用的 SQL Server 实例为分布式缓存后备存储。
2.IDistributedCache简单封装
/// <summary> /// <see cref="IDistributedCache"/>扩展方法 /// </summary> public static class DistributedCacheExtensions { /// <summary> /// 将对象存入缓存中 /// </summary> public static void SetCache(this IDistributedCache cache, string key, object value, DistributedCacheEntryOptions options = null) { string json = JsonConvert.SerializeObject(value); if (options == null) { cache.SetString(key, json); } else { cache.SetString(key, json, options); } } /// <summary> /// 异步将对象存入缓存中 /// </summary> public static async Task SetCacheAsync(this IDistributedCache cache, string key, object value, DistributedCacheEntryOptions options = null) { string json = JsonConvert.SerializeObject(value); if (options == null) { await cache.SetStringAsync(key, json); } else { await cache.SetStringAsync(key, json, options); } } /// <summary> /// 将对象存入缓存中,使用指定时长 /// </summary> public static void Set(this IDistributedCache cache, string key, object value, int cacheSeconds) { DistributedCacheEntryOptions options = new DistributedCacheEntryOptions(); options.SetAbsoluteExpiration(TimeSpan.FromSeconds(cacheSeconds)); cache.SetCache(key, value, options); } /// <summary> /// 异步将对象存入缓存中,使用指定时长 /// </summary> public static Task SetAsync(this IDistributedCache cache, string key, object value, int cacheSeconds) { DistributedCacheEntryOptions options = new DistributedCacheEntryOptions(); options.SetAbsoluteExpiration(TimeSpan.FromSeconds(cacheSeconds)); return cache.SetCacheAsync(key, value, options); } /// <summary> /// 将对象存入缓存中,使用功能配置 /// </summary> public static void Set(this IDistributedCache cache, string key, object value, DistributedCacheEntryOptions cacheOptions) { if (cacheOptions == null) { return; } cache.SetCache(key, value, cacheOptions); } /// <summary> /// 异步将对象存入缓存中,使用功能配置 /// </summary> public static Task SetAsync(this IDistributedCache cache, string key, object value, DistributedCacheEntryOptions cacheOptions) { if (cacheOptions == null) { return Task.FromResult(0); } return cache.SetCacheAsync(key, value, cacheOptions); } /// <summary> /// 获取指定键的缓存项 /// </summary> public static TResult Get<TResult>(this IDistributedCache cache, string key) { string json = cache.GetString(key); if (json == null) { return default(TResult); } return JsonConvert.DeserializeObject<TResult>(json); } /// <summary> /// 异步获取指定键的缓存项 /// </summary> public static async Task<TResult> GetAsync<TResult>(this IDistributedCache cache, string key) { string json = await cache.GetStringAsync(key); if (json == null) { return default(TResult); } return JsonConvert.DeserializeObject<TResult>(json); } /// <summary> /// 获取指定键的缓存项,不存在则从指定委托获取,并回存到缓存中再返回 /// </summary> public static TResult GetCache<TResult>(this IDistributedCache cache, string key, Func<TResult> getFunc, DistributedCacheEntryOptions options = null) { TResult result = cache.Get<TResult>(key); if (!Equals(result, default(TResult))) { return result; } result = getFunc(); if (Equals(result, default(TResult))) { return default(TResult); } cache.SetCache(key, result, options); return result; } /// <summary> /// 异步获取指定键的缓存项,不存在则从指定委托获取,并回存到缓存中再返回 /// </summary> public static async Task<TResult> GetCacheAsync<TResult>(this IDistributedCache cache, string key, Func<Task<TResult>> getAsyncFunc, DistributedCacheEntryOptions options = null) { TResult result = await cache.GetAsync<TResult>(key); if (!Equals(result, default(TResult))) { return result; } result = await getAsyncFunc(); if (Equals(result, default(TResult))) { return default(TResult); } await cache.SetCacheAsync(key, result, options); return result; } /// <summary> /// 获取指定键的缓存项,不存在则从指定委托获取,并回存到缓存中再返回 /// </summary> public static TResult Get<TResult>(this IDistributedCache cache, string key, Func<TResult> getFunc, int cacheSeconds) { DistributedCacheEntryOptions options = new DistributedCacheEntryOptions(); options.SetAbsoluteExpiration(TimeSpan.FromSeconds(cacheSeconds)); return cache.GetCache<TResult>(key, getFunc, options); } /// <summary> /// 异步获取指定键的缓存项,不存在则从指定委托获取,并回存到缓存中再返回 /// </summary> public static Task<TResult> GetAsync<TResult>(this IDistributedCache cache, string key, Func<Task<TResult>> getAsyncFunc, int cacheSeconds) { DistributedCacheEntryOptions options = new DistributedCacheEntryOptions(); options.SetAbsoluteExpiration(TimeSpan.FromSeconds(cacheSeconds)); return cache.GetAsync<TResult>(key, getAsyncFunc, options); } /// <summary> /// 获取指定键的缓存项,不存在则从指定委托获取,并回存到缓存中再返回 /// </summary> public static TResult Get<TResult>(this IDistributedCache cache, string key, Func<TResult> getFunc, DistributedCacheEntryOptions cacheOptions) { if (cacheOptions == null) { return getFunc(); } return cache.Get<TResult>(key, getFunc, cacheOptions); } /// <summary> /// 获取指定键的缓存项,不存在则从指定委托获取,并回存到缓存中再返回 /// </summary> public static Task<TResult> GetAsync<TResult>(this IDistributedCache cache, string key, Func<Task<TResult>> getAsyncFunc, DistributedCacheEntryOptions cacheOptions) { if (cacheOptions == null) { return getAsyncFunc(); } return cache.GetAsync<TResult>(key, getAsyncFunc, cacheOptions); } }