提供缓冲支持,目前支持内存缓冲器和redis缓冲器
This commit is contained in:
parent
4aa3936754
commit
4b93c9f129
127
Falcon.SugarApi.Test/CacheTest.cs
Normal file
127
Falcon.SugarApi.Test/CacheTest.cs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Falcon.SugarApi.Cache;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Falcon.SugarApi.Test
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class CacheTest
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void MemoryTest() {
|
||||||
|
var sw = new Stopwatch();
|
||||||
|
var services = new ServiceCollection() as IServiceCollection;
|
||||||
|
services.AddSugarMemoryCache(op => {
|
||||||
|
|
||||||
|
});
|
||||||
|
var ts = new TimeSpan(0, 1, 0);
|
||||||
|
var strResult = "";
|
||||||
|
int runTimes = 10000;
|
||||||
|
var sp = services.BuildServiceProvider().CreateScope().ServiceProvider;
|
||||||
|
var sc = sp.GetService<ISugarCache>();
|
||||||
|
var sca = sp.GetService<ISugarCacheAsync>();
|
||||||
|
|
||||||
|
var key = Guid.NewGuid().ToString();
|
||||||
|
var strValue = Guid.NewGuid().ToString();
|
||||||
|
//字符串同步存储
|
||||||
|
Assert.IsNotNull(sc);
|
||||||
|
sw.Restart();
|
||||||
|
sc.SetStringValue(key, strValue, ts);
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"SetStringValue 一次执行时间{sw.ElapsedMilliseconds}毫秒");
|
||||||
|
sw.Restart();
|
||||||
|
strResult = sc.GetStringValue(key);
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"GetStringValue 一次执行时间{sw.ElapsedMilliseconds}毫秒");
|
||||||
|
Assert.IsTrue(strResult == strValue);
|
||||||
|
strValue = Guid.NewGuid().ToString();
|
||||||
|
sc.SetStringValue(key, strValue, ts);
|
||||||
|
strResult = sc.GetStringValue(key);
|
||||||
|
Assert.IsTrue(strResult == strValue);
|
||||||
|
sw.Restart();
|
||||||
|
for (int i = 0; i < runTimes; i++) {
|
||||||
|
strResult = sc.GetStringValue(key);
|
||||||
|
Assert.IsTrue(strResult == strValue);
|
||||||
|
}
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"GetStringValue {runTimes}次执行时间{sw.ElapsedMilliseconds}毫秒");
|
||||||
|
|
||||||
|
//字符串异步存储
|
||||||
|
Assert.IsNotNull(sca);
|
||||||
|
sw.Restart();
|
||||||
|
sca.SetStringValueAsync(key, strValue, ts).Wait();
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"SetStringValueAsync 一次执行时间{sw.ElapsedMilliseconds}毫秒");
|
||||||
|
|
||||||
|
strResult = Guid.NewGuid().ToString();
|
||||||
|
sw.Restart();
|
||||||
|
strResult = sca.GetStringValueAsync(key).Result;
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"GetStringValueAsync 一次执行时间{sw.ElapsedMilliseconds}毫秒");
|
||||||
|
Assert.IsTrue(strResult == strValue);
|
||||||
|
strValue = Guid.NewGuid().ToString();
|
||||||
|
sca.SetStringValueAsync(key, strValue, ts).Wait();
|
||||||
|
strResult = sca.GetStringValueAsync(key).Result;
|
||||||
|
Assert.IsTrue(strResult == strValue);
|
||||||
|
sw.Restart();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
strResult = sca.GetStringValueAsync(key).Result;
|
||||||
|
Assert.IsTrue(strResult == strValue);
|
||||||
|
}
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"GetStringValueAsync {runTimes}次执行时间{sw.ElapsedMilliseconds}毫秒");
|
||||||
|
|
||||||
|
//对象同步存储
|
||||||
|
var obj = new CacheTestModel {
|
||||||
|
Id = 1, Name = "name1"
|
||||||
|
};
|
||||||
|
sw.Restart();
|
||||||
|
sc.SetValue(key, obj, ts);
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"SetValue 一次执行时间{sw.ElapsedMilliseconds}毫秒");
|
||||||
|
sw.Restart();
|
||||||
|
var objResult = sc.GetValue<CacheTestModel>(key);
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"GetValue 一次执行时间{sw.ElapsedMilliseconds}毫秒");
|
||||||
|
Assert.IsTrue(obj.Equals(objResult));
|
||||||
|
//对象异步存储
|
||||||
|
sw.Restart();
|
||||||
|
sca.SetValueAsync(key, obj, ts);
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"SetValueAsync 一次执行时间{sw.ElapsedMilliseconds}毫秒");
|
||||||
|
objResult = null;
|
||||||
|
sw.Restart();
|
||||||
|
objResult = sca.GetValueAsync<CacheTestModel>(key).Result;
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"GetValueAsync 一次执行时间{sw.ElapsedMilliseconds}毫秒");
|
||||||
|
Assert.IsTrue(obj.Equals(objResult));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal class CacheTestModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public override bool Equals(object? obj) {
|
||||||
|
Console.WriteLine("对象比较");
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (obj is CacheTestModel o) {
|
||||||
|
return o.Id == this.Id && o.Name == this.Name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
|
||||||
|
namespace Falcon.SugarApi.Cache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 分布式缓冲选项
|
||||||
|
/// </summary>
|
||||||
|
internal class DistributedCacheEntryOptionsWallPaper : DistributedCacheEntryOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 通过过期时间段实例化DistributedCacheEntryOptions
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeSpan">时间段</param>
|
||||||
|
public DistributedCacheEntryOptionsWallPaper(TimeSpan timeSpan) {
|
||||||
|
this.AbsoluteExpirationRelativeToNow = timeSpan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
Falcon.SugarApi/Cache/IServiceCollectionExtend.cs
Normal file
42
Falcon.SugarApi/Cache/IServiceCollectionExtend.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using Falcon.SugarApi.JsonSerialize;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Microsoft.Extensions.Caching.StackExchangeRedis;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Falcon.SugarApi.Cache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 服务集合扩展
|
||||||
|
/// </summary>
|
||||||
|
public static class IServiceCollectionExtend
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 注册Redis缓冲服务器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">服务集合</param>
|
||||||
|
/// <param name="configRedis">缓冲配置</param>
|
||||||
|
/// <returns>服务集合</returns>
|
||||||
|
public static IServiceCollection AddSugarRedisCache(this IServiceCollection services, Action<RedisCacheOptions> configRedis) {
|
||||||
|
services.AddSingleton<JsonSerializeFactory>(_ => new JsonSerializeFactory());
|
||||||
|
services.AddStackExchangeRedisCache(configRedis);
|
||||||
|
services.AddSingleton<ISugarCache, SugarCache>();
|
||||||
|
services.AddSingleton<ISugarCacheAsync, SugarCache>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册内存缓冲服务器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">服务结合</param>
|
||||||
|
/// <param name="configAction">缓冲配置</param>
|
||||||
|
/// <returns>服务结合</returns>
|
||||||
|
public static IServiceCollection AddSugarMemoryCache(this IServiceCollection services, Action<MemoryDistributedCacheOptions> configAction) {
|
||||||
|
services.AddSingleton<JsonSerializeFactory>(_ => new JsonSerializeFactory());
|
||||||
|
services.AddDistributedMemoryCache(configAction);
|
||||||
|
services.AddSingleton<ISugarCache, SugarCache>();
|
||||||
|
services.AddSingleton<ISugarCacheAsync, SugarCache>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
Falcon.SugarApi/Cache/ISugarCache.cs
Normal file
41
Falcon.SugarApi/Cache/ISugarCache.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Falcon.SugarApi.Cache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 提供数据缓冲支持
|
||||||
|
/// </summary>
|
||||||
|
public interface ISugarCache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取缓冲对象
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">缓存键</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
T? GetValue<T>([NotNull] string key) where T : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取缓存的字符串值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">缓存键</param>
|
||||||
|
/// <returns>缓冲值</returns>
|
||||||
|
string GetStringValue([NotNull] string key);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置对象缓冲
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">缓冲键</param>
|
||||||
|
/// <param name="value">缓冲值</param>
|
||||||
|
/// <param name="cacheTimeSpan">缓冲时长</param>
|
||||||
|
void SetValue<T>([NotNull] string key, T value, TimeSpan cacheTimeSpan) where T : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存字符串值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">缓存键</param>
|
||||||
|
/// <param name="value">缓冲值</param>
|
||||||
|
/// <param name="cacheTimeSpan">缓冲时长</param>
|
||||||
|
void SetStringValue([NotNull] string key, string value, TimeSpan cacheTimeSpan);
|
||||||
|
}
|
||||||
|
}
|
47
Falcon.SugarApi/Cache/ISugarCacheAsync.cs
Normal file
47
Falcon.SugarApi/Cache/ISugarCacheAsync.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Falcon.SugarApi.Cache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 提供数据缓冲支持
|
||||||
|
/// </summary>
|
||||||
|
public interface ISugarCacheAsync
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取字符串换重置
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<T?> GetValueAsync<T>([NotNull] string key, CancellationToken cancellationToken = default) where T : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取字符串换重置
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<string?> GetStringValueAsync([NotNull] string key, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置字符串缓冲
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">缓冲键</param>
|
||||||
|
/// <param name="value">缓冲值</param>
|
||||||
|
/// <param name="cacheTimeSpan">缓冲时长</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
Task SetValueAsync<T>([NotNull] string key, T value, TimeSpan cacheTimeSpan, CancellationToken cancellationToken = default) where T : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置字符串缓冲
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">缓冲键</param>
|
||||||
|
/// <param name="value">缓冲值</param>
|
||||||
|
/// <param name="cacheTimeSpan">缓冲时长</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
Task SetStringValueAsync([NotNull] string key, string value, TimeSpan cacheTimeSpan, CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
|
}
|
6
Falcon.SugarApi/Cache/Readme.md
Normal file
6
Falcon.SugarApi/Cache/Readme.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
## 缓冲器
|
||||||
|
> 使用 `IServiceCollection.AddSugarRedisCache` 或 `IServiceCollection.AddSugarMemoryCache` 注册缓冲器即可
|
||||||
|
> 在使用时注入 `ISugarCache`同步接口 或 `ISugarCacheAsync`异步接口
|
||||||
|
> 接口的`Get`和`Set`方法分别对应获取和保存缓冲值。
|
||||||
|
|
||||||
|
> 在可能的情况下尽量使用异步方法,异步效率远远高于同步方法。
|
95
Falcon.SugarApi/Cache/SugarCache.cs
Normal file
95
Falcon.SugarApi/Cache/SugarCache.cs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Falcon.SugarApi.JsonSerialize;
|
||||||
|
using Microsoft.Extensions.Caching;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
|
||||||
|
namespace Falcon.SugarApi.Cache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 缓冲器
|
||||||
|
/// </summary>
|
||||||
|
public class SugarCache : ISugarCache, ISugarCacheAsync
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 内部缓冲提供器实现
|
||||||
|
/// </summary>
|
||||||
|
public IDistributedCache CacheProvider { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 序列化提供器
|
||||||
|
/// </summary>
|
||||||
|
public IJsonSerialize Json { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造缓冲器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cache">基础分布式缓冲器</param>
|
||||||
|
/// <param name="factory">Json序列化工厂</param>
|
||||||
|
public SugarCache(IDistributedCache cache, JsonSerializeFactory factory) {
|
||||||
|
this.CacheProvider = cache;
|
||||||
|
Json = factory.CreateJsonSerialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public T? GetValue<T>([NotNull] string key) where T : class {
|
||||||
|
var str = GetStringValue(key);
|
||||||
|
return str.IsNullOrEmpty() ? null : Json.Deserialize<T>(str);
|
||||||
|
}
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string GetStringValue([NotNull] string key) {
|
||||||
|
return this.CacheProvider.GetString(key);
|
||||||
|
}
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void SetValue<T>([NotNull] string key, T value, TimeSpan cacheTimeSpan) where T : class {
|
||||||
|
if (value == null) {
|
||||||
|
CacheProvider.Remove(key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var str = Json.Serialize(value);
|
||||||
|
CacheProvider.SetString(key, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void SetStringValue([NotNull] string key, string value, TimeSpan cacheTimeSpan) {
|
||||||
|
CacheProvider.SetString(key, value, new DistributedCacheEntryOptionsWallPaper(cacheTimeSpan));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<T?> GetValueAsync<T>([NotNull] string key, CancellationToken cancellationToken = default) where T : class {
|
||||||
|
var str = await CacheProvider.GetStringAsync(key, cancellationToken);
|
||||||
|
if (str.IsNullOrEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Json.Deserialize<T>(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<string?> GetStringValueAsync([NotNull] string key, CancellationToken cancellationToken = default) {
|
||||||
|
return await CacheProvider.GetStringAsync(key, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task SetValueAsync<T>([NotNull] string key, T value, TimeSpan cacheTimeSpan, CancellationToken cancellationToken = default) where T : class {
|
||||||
|
if (value == null) {
|
||||||
|
await CacheProvider.RemoveAsync(key, cancellationToken);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var str = Json.Serialize(value);
|
||||||
|
await CacheProvider.SetStringAsync(key, str, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task SetStringValueAsync([NotNull] string key, string value, TimeSpan cacheTimeSpan, CancellationToken cancellationToken = default) {
|
||||||
|
if (value == null) {
|
||||||
|
await CacheProvider.RemoveAsync(key, cancellationToken);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await CacheProvider.SetStringAsync(key, value, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,17 +11,21 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
<!--<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />-->
|
||||||
<PackageReference Include="SqlSugarCore" Version="5.0.6.1" />
|
<PackageReference Include="SqlSugarCore" Version="5.0.6.1" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.6.3" />
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.6.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net5' ">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'net5' ">
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="5.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net6' ">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'net6' ">
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="6.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user