diff --git a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/CacheEntry.cs b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/CacheEntry.cs index 0d655b43d..937763dfe 100644 --- a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/CacheEntry.cs +++ b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/CacheEntry.cs @@ -3,7 +3,7 @@ namespace Masa.BuildingBlocks.Caching; -public class CacheEntry : CacheEntryOptions +public class CacheEntry : CacheEntryOptionsBase { public T? Value { get; } @@ -12,9 +12,9 @@ public CacheEntry(T? value) Value = value; } - public CacheEntry(T value, DateTimeOffset absoluteExpiration) : this(value) + public CacheEntry(T? value, DateTimeOffset absoluteExpiration) : this(value) => AbsoluteExpiration = absoluteExpiration; - public CacheEntry(T value, TimeSpan absoluteExpirationRelativeToNow) : this(value) + public CacheEntry(T? value, TimeSpan absoluteExpirationRelativeToNow) : this(value) => AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow; } diff --git a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DefaultDistributedCacheClient.cs b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DefaultDistributedCacheClient.cs index bafb48ade..963f82967 100644 --- a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DefaultDistributedCacheClient.cs +++ b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DefaultDistributedCacheClient.cs @@ -7,7 +7,7 @@ namespace Masa.BuildingBlocks.Caching; -internal class DefaultDistributedCacheClient : DefaultCacheClient, IManualDistributedCacheClient +internal sealed class DefaultDistributedCacheClient : DefaultCacheClient, IManualDistributedCacheClient { private readonly IManualDistributedCacheClient _cacheClient; public DefaultDistributedCacheClient(IManualDistributedCacheClient cacheClient) : base(cacheClient) => _cacheClient = cacheClient; @@ -155,13 +155,7 @@ public Task KeyExpireAsync(IEnumerable keys, CacheEntryOptions? #pragma warning disable S3881 public void Dispose() { - Dispose(true); GC.SuppressFinalize(this); } - - protected virtual void Dispose(bool disposing) - { - //don't need to be released - } #pragma warning restore S3881 } diff --git a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DefaultMultilevelCacheClient.cs b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DefaultMultilevelCacheClient.cs index d1063595a..799492d8e 100644 --- a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DefaultMultilevelCacheClient.cs +++ b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DefaultMultilevelCacheClient.cs @@ -7,7 +7,7 @@ namespace Masa.BuildingBlocks.Caching; -internal class DefaultMultilevelCacheClient : DefaultCacheClient, IManualMultilevelCacheClient +internal sealed class DefaultMultilevelCacheClient : DefaultCacheClient, IManualMultilevelCacheClient { private readonly IManualMultilevelCacheClient _cacheClient; @@ -115,13 +115,7 @@ public Task SetListAsync(Dictionary keyValues, CombinedCacheEntry #pragma warning disable S3881 public void Dispose() { - Dispose(true); GC.SuppressFinalize(this); } - - protected virtual void Dispose(bool disposing) - { - //don't need to be released - } #pragma warning restore S3881 } diff --git a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/ServiceCollectionExtensions.Core.cs b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/ServiceCollectionExtensions.Core.cs index e0f0c39ed..67ed3f85b 100644 --- a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/ServiceCollectionExtensions.Core.cs +++ b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/ServiceCollectionExtensions.Core.cs @@ -3,6 +3,7 @@ [assembly: InternalsVisibleTo("Masa.Contrib.Caching.Distributed.StackExchangeRedis")] [assembly: InternalsVisibleTo("Masa.Contrib.Caching.MultilevelCache")] + // ReSharper disable once CheckNamespace namespace Masa.BuildingBlocks.Caching; diff --git a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Options/CacheEntryOptions.cs b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Options/CacheEntryOptions.cs index 6fa712521..36ae31b8d 100644 --- a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Options/CacheEntryOptions.cs +++ b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Options/CacheEntryOptions.cs @@ -2,84 +2,66 @@ // Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ReSharper disable once CheckNamespace -namespace Masa.BuildingBlocks.Caching -{ - public class CacheEntryOptions - { - private TimeSpan? _absoluteExpirationRelativeToNow; - private TimeSpan? _slidingExpiration; - /// - /// Gets or sets an absolute expiration date for the cache entry. - /// When coexisting with AbsoluteExpirationRelativeToNow, use AbsoluteExpirationRelativeToNow first - /// - public DateTimeOffset? AbsoluteExpiration { get; set; } +namespace Masa.BuildingBlocks.Caching; - /// - /// Gets or sets an absolute expiration time, relative to now. - /// When coexisting with AbsoluteExpiration, use AbsoluteExpirationRelativeToNow first - /// - public TimeSpan? AbsoluteExpirationRelativeToNow - { - get => _absoluteExpirationRelativeToNow; - set - { - if (value <= TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException( - nameof(AbsoluteExpirationRelativeToNow), - value, - "The relative expiration value must be positive."); - } +public class CacheEntryOptions +{ + private TimeSpan? _absoluteExpirationRelativeToNow; + private TimeSpan? _slidingExpiration; - _absoluteExpirationRelativeToNow = value; - } - } + /// + /// Gets or sets an absolute expiration date for the cache entry. + /// When coexisting with AbsoluteExpirationRelativeToNow, use AbsoluteExpirationRelativeToNow first + /// + public DateTimeOffset? AbsoluteExpiration { get; set; } - /// - /// Gets or sets how long a cache entry can be inactive (e.g. not accessed) before it will be removed. - /// This will not extend the entry lifetime beyond the absolute expiration (if set). - /// - public TimeSpan? SlidingExpiration + /// + /// Gets or sets an absolute expiration time, relative to now. + /// When coexisting with AbsoluteExpiration, use AbsoluteExpirationRelativeToNow first + /// + public TimeSpan? AbsoluteExpirationRelativeToNow + { + get => _absoluteExpirationRelativeToNow; + set { - get => _slidingExpiration; - set + if (value <= TimeSpan.Zero) { - if (value <= TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException( - nameof(SlidingExpiration), - value, - "The sliding expiration value must be positive."); - } - _slidingExpiration = value; + throw new ArgumentOutOfRangeException( + nameof(AbsoluteExpirationRelativeToNow), + value, + "The relative expiration value must be positive."); } - } - - public CacheEntryOptions() { } - - public CacheEntryOptions(DateTimeOffset? absoluteExpiration) - => AbsoluteExpiration = absoluteExpiration; - public CacheEntryOptions(TimeSpan? absoluteExpirationRelativeToNow) - => AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow; + _absoluteExpirationRelativeToNow = value; + } } - public class CacheEntryOptions : CacheEntryOptions + /// + /// Gets or sets how long a cache entry can be inactive (e.g. not accessed) before it will be removed. + /// This will not extend the entry lifetime beyond the absolute expiration (if set). + /// + public TimeSpan? SlidingExpiration { - public Action? ValueChanged { get; set; } - - public CacheEntryOptions() + get => _slidingExpiration; + set { + if (value <= TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException( + nameof(SlidingExpiration), + value, + "The sliding expiration value must be positive."); + } + _slidingExpiration = value; } + } - public CacheEntryOptions(DateTimeOffset? absoluteExpiration) : base(absoluteExpiration) - { - } + public CacheEntryOptions() { } - public CacheEntryOptions(TimeSpan? absoluteExpirationRelativeToNow) : base(absoluteExpirationRelativeToNow) - { + public CacheEntryOptions(DateTimeOffset? absoluteExpiration) + => AbsoluteExpiration = absoluteExpiration; - } - } + public CacheEntryOptions(TimeSpan? absoluteExpirationRelativeToNow) + => AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow; } diff --git a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Options/CacheEntryOptionsBase.cs b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Options/CacheEntryOptionsBase.cs new file mode 100644 index 000000000..7df5a69c8 --- /dev/null +++ b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Options/CacheEntryOptionsBase.cs @@ -0,0 +1,72 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +// ReSharper disable once CheckNamespace + +namespace Masa.BuildingBlocks.Caching; + +public abstract class CacheEntryOptionsBase +{ + #region Set the expiration time to ensure that the writing method remains unchanged + + /// + /// Gets or sets an absolute expiration date for the cache entry. + /// When coexisting with AbsoluteExpirationRelativeToNow, use AbsoluteExpirationRelativeToNow first + /// + public DateTimeOffset? AbsoluteExpiration + { + get => CacheOptions?.AbsoluteExpiration; + set + { + CacheOptions ??= new CacheEntryOptions(); + CacheOptions.AbsoluteExpiration = value; + } + } + + /// + /// Gets or sets an absolute expiration time, relative to now. + /// When coexisting with AbsoluteExpiration, use AbsoluteExpirationRelativeToNow first + /// + public TimeSpan? AbsoluteExpirationRelativeToNow + { + get => CacheOptions?.AbsoluteExpirationRelativeToNow; + set + { + CacheOptions ??= new CacheEntryOptions(); + CacheOptions.AbsoluteExpirationRelativeToNow = value; + } + } + + /// + /// Gets or sets how long a cache entry can be inactive (e.g. not accessed) before it will be removed. + /// This will not extend the entry lifetime beyond the absolute expiration (if set). + /// + public TimeSpan? SlidingExpiration + { + get => CacheOptions?.SlidingExpiration; + set + { + CacheOptions ??= new CacheEntryOptions(); + CacheOptions.SlidingExpiration = value; + } + } + + #endregion + + public CacheEntryOptions? CacheOptions { get; set; } + + protected CacheEntryOptionsBase() + { + CacheOptions = null; + } + + protected CacheEntryOptionsBase(DateTimeOffset? absoluteExpiration) : this() + { + AbsoluteExpiration = absoluteExpiration; + } + + protected CacheEntryOptionsBase(TimeSpan? absoluteExpirationRelativeToNow) : this() + { + AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow; + } +} diff --git a/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClient.cs b/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClient.cs index 0f33cab1d..4beab37e9 100644 --- a/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClient.cs +++ b/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClient.cs @@ -98,7 +98,7 @@ private async Task>> GetListAsync(List keys) if (cacheEntry.Value == null) return default; - SetCoreAsync(key, cacheEntry.Value, cacheEntry).ConfigureAwait(false).GetAwaiter().GetResult(); + SetCoreAsync(key, cacheEntry.Value, cacheEntry.CacheOptions).ConfigureAwait(false).GetAwaiter().GetResult(); return cacheEntry.Value; }); } @@ -120,7 +120,7 @@ private async Task>> GetListAsync(List keys) if (cacheEntry.Value == null) return default; - await SetCoreAsync(key, cacheEntry.Value, cacheEntry).ConfigureAwait(false); + await SetCoreAsync(key, cacheEntry.Value, cacheEntry.CacheOptions).ConfigureAwait(false); return cacheEntry.Value; }).ConfigureAwait(false); } diff --git a/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClientBase.cs b/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClientBase.cs index d591f0577..20cf755e2 100644 --- a/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClientBase.cs +++ b/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClientBase.cs @@ -38,15 +38,15 @@ protected RedisCacheClientBase( private RedisCacheClientBase( CacheOptions globalCacheOptions, - CacheEntryOptions expiredEntryOptions, + CacheEntryOptions globalExpiredOptions, JsonSerializerOptions? jsonSerializerOptions) { _globalCacheOptions = globalCacheOptions; _globalCacheEntryOptions = new CacheEntryOptions { - AbsoluteExpiration = expiredEntryOptions.AbsoluteExpiration, - AbsoluteExpirationRelativeToNow = expiredEntryOptions.AbsoluteExpirationRelativeToNow, - SlidingExpiration = expiredEntryOptions.SlidingExpiration + AbsoluteExpiration = globalExpiredOptions.AbsoluteExpiration, + AbsoluteExpirationRelativeToNow = globalExpiredOptions.AbsoluteExpirationRelativeToNow, + SlidingExpiration = globalExpiredOptions.SlidingExpiration }; GlobalJsonSerializerOptions = jsonSerializerOptions ?? new JsonSerializerOptions().EnableDynamicTypes(); } diff --git a/src/Contrib/Caching/Distributed/Tests/Masa.Contrib.Caching.Distributed.StackExchangeRedis.Tests/DistributedCacheClientTest.cs b/src/Contrib/Caching/Distributed/Tests/Masa.Contrib.Caching.Distributed.StackExchangeRedis.Tests/DistributedCacheClientTest.cs index e7b2cd0ad..c2fe92854 100644 --- a/src/Contrib/Caching/Distributed/Tests/Masa.Contrib.Caching.Distributed.StackExchangeRedis.Tests/DistributedCacheClientTest.cs +++ b/src/Contrib/Caching/Distributed/Tests/Masa.Contrib.Caching.Distributed.StackExchangeRedis.Tests/DistributedCacheClientTest.cs @@ -26,7 +26,7 @@ public void Initialize() public async Task SetAsync(string key, string value) { await _distributedCacheClient.RemoveAsync(key); - await _distributedCacheClient.SetAsync(key, value, new CacheEntryOptions(TimeSpan.FromMinutes(1)) + await _distributedCacheClient.SetAsync(key, value, new CacheEntryOptions(TimeSpan.FromMinutes(1)) { SlidingExpiration = TimeSpan.FromSeconds(30) }); @@ -41,7 +41,7 @@ public async Task SetAsync(string key, string value) public void Set(string key, string value) { _distributedCacheClient.Remove(key); - _distributedCacheClient.Set(key, value, new CacheEntryOptions(TimeSpan.FromMinutes(1)) + _distributedCacheClient.Set(key, value, new CacheEntryOptions(TimeSpan.FromMinutes(1)) { SlidingExpiration = TimeSpan.FromSeconds(30) }); @@ -68,9 +68,7 @@ public void SetAndSpecifyTimeSpan(string key, string value) public async Task SetAndSpecifyTimeSpanAsync(string key, string value) { await _distributedCacheClient.SetAsync(key, value, TimeSpan.FromSeconds(30)); - var expireTimeSpan = await _database.KeyTimeToLiveAsync(key); - Assert.IsNotNull(expireTimeSpan); - Assert.IsTrue(expireTimeSpan.Value.TotalSeconds is <= 30 and >= 25); + CheckLifeCycle(_database, key, 25, 30); await _distributedCacheClient.RemoveAsync(key); } @@ -79,9 +77,7 @@ public async Task SetAndSpecifyTimeSpanAsync(string key, string value) public void SetAndSpecifyTime(string key, string value) { _distributedCacheClient.Set(key, value, DateTimeOffset.Now.AddMinutes(1)); - var expireTimeSpan = _database.KeyTimeToLive(key); - Assert.IsNotNull(expireTimeSpan); - Assert.IsTrue(expireTimeSpan.Value.TotalSeconds is <= 60 and >= 55); + CheckLifeCycle(_database, key, 55, 60); _distributedCacheClient.Remove(key); } @@ -90,12 +86,38 @@ public void SetAndSpecifyTime(string key, string value) public async Task SetAndSpecifyTimeAsync(string key, string value) { await _distributedCacheClient.SetAsync(key, value, DateTimeOffset.Now.AddMinutes(1)); - var expireTimeSpan = await _database.KeyTimeToLiveAsync(key); - Assert.IsNotNull(expireTimeSpan); - Assert.IsTrue(expireTimeSpan.Value.TotalSeconds is <= 60 and >= 55); + CheckLifeCycle(_database, key, 55, 60); await _distributedCacheClient.RemoveAsync(key); } + [DataTestMethod] + [DataRow("cache_test", "content")] + public async Task SetAndSpecifyTimeAsyncAndUseGlobalOptions(string key, string value) + { + var globalRedisConfigurationOptions = GetConfigurationOptions(); + globalRedisConfigurationOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60); + var distributedCacheClient = new RedisCacheClient(globalRedisConfigurationOptions); + var database = (await ConnectionMultiplexer.ConnectAsync(globalRedisConfigurationOptions)).GetDatabase(); + + await distributedCacheClient.SetAsync(key, value); + CheckLifeCycle(database, key, 55, 60); + await distributedCacheClient.RemoveAsync(key); + } + + [DataTestMethod] + [DataRow("cache_test", "content")] + public void SetAndSpecifyTimeAndUseGlobalOptions(string key, string value) + { + var globalRedisConfigurationOptions = GetConfigurationOptions(); + globalRedisConfigurationOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60); + var distributedCacheClient = new RedisCacheClient(globalRedisConfigurationOptions); + var database = ConnectionMultiplexer.Connect(globalRedisConfigurationOptions).GetDatabase(); + + distributedCacheClient.Set(key, value); + CheckLifeCycle(database, key, 55, 60); + distributedCacheClient.Remove(key); + } + [DataTestMethod] [DataRow("cache_test_sync", "2022-01-01")] public void SetByDateTime(string key, string value) @@ -423,6 +445,9 @@ public void TestGetOrSet(string key, string? value) }); Assert.AreEqual(value, res); + var expireTimeSpan = _database.KeyTimeToLive(key); + + _distributedCacheClient.Remove(key); } diff --git a/src/Contrib/Caching/Distributed/Tests/Masa.Contrib.Caching.Distributed.StackExchangeRedis.Tests/TestBase.cs b/src/Contrib/Caching/Distributed/Tests/Masa.Contrib.Caching.Distributed.StackExchangeRedis.Tests/TestBase.cs index 1c2b1fa39..3a21566c4 100644 --- a/src/Contrib/Caching/Distributed/Tests/Masa.Contrib.Caching.Distributed.StackExchangeRedis.Tests/TestBase.cs +++ b/src/Contrib/Caching/Distributed/Tests/Masa.Contrib.Caching.Distributed.StackExchangeRedis.Tests/TestBase.cs @@ -35,4 +35,11 @@ protected static JsonSerializerOptions GetJsonSerializerOptions() jsonSerializerOptions.EnableDynamicTypes(); return jsonSerializerOptions; } + + public static void CheckLifeCycle(IDatabase database, string key, double minVal, double maxVal) + { + var expireTimeSpan = database.KeyTimeToLive(key); + Assert.IsNotNull(expireTimeSpan); + Assert.IsTrue(expireTimeSpan.Value.TotalSeconds <= maxVal && expireTimeSpan.Value.TotalSeconds >= minVal); + } } diff --git a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/MultilevelCacheClientTest.cs b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/MultilevelCacheClientTest.cs index 4c86843e1..9cd9dea50 100644 --- a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/MultilevelCacheClientTest.cs +++ b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/MultilevelCacheClientTest.cs @@ -655,13 +655,15 @@ private void InitializeData() _distributedCacheClient.Set("test_multilevel_cache_2", 99.99m); } - private static IManualMultilevelCacheClient InitializeByCacheEntryOptionsIsNull() + private static IManualMultilevelCacheClient InitializeByCacheEntryOptionsIsNull( + RedisConfigurationOptions? redisConfigurationOptions = null, + Action? multilevelCacheOptionsAction = null) { var services = new ServiceCollection(); services.AddMultilevelCache("test", distributedCacheBuilder => { - distributedCacheBuilder.UseStackExchangeRedisCache(RedisConfigurationOptions); - }); + distributedCacheBuilder.UseStackExchangeRedisCache(redisConfigurationOptions ?? RedisConfigurationOptions); + }, multilevelCacheOptionsAction); var serviceProvider = services.BuildServiceProvider(); var cacheClientFactory = serviceProvider.GetRequiredService(); var multilevelCacheClient = cacheClientFactory.Create("test"); @@ -723,6 +725,48 @@ public async Task TestSetBySpecifiedTimeAsync() Assert.AreEqual(null, await multilevelCacheClient.GetAsync(key)); } + [DataTestMethod] + [DataRow("cache_test", "content")] + public async Task SetAndSpecifyTimeAsyncAndUseGlobalOptions(string key, string value) + { + var globalRedisConfigurationOptions = RedisConfigurationOptions; + globalRedisConfigurationOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60); + using var multilevelCacheClient = InitializeByCacheEntryOptionsIsNull(globalRedisConfigurationOptions, options => + { + options.GlobalCacheOptions = new CacheOptions() + { + CacheKeyType = CacheKeyType.None + }; + }); + + var database = (await ConnectionMultiplexer.ConnectAsync(globalRedisConfigurationOptions)).GetDatabase(); + + await multilevelCacheClient.SetAsync(key, value); + CheckLifeCycle(database, key, 55, 60); + await multilevelCacheClient.RemoveAsync(key); + } + + [DataTestMethod] + [DataRow("cache_test", "content")] + public void SetAndSpecifyTimeAndUseGlobalOptions(string key, string value) + { + var globalRedisConfigurationOptions = RedisConfigurationOptions; + globalRedisConfigurationOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60); + using var multilevelCacheClient = InitializeByCacheEntryOptionsIsNull(globalRedisConfigurationOptions, options => + { + options.GlobalCacheOptions = new CacheOptions() + { + CacheKeyType = CacheKeyType.None + }; + }); + + var database = ConnectionMultiplexer.Connect(globalRedisConfigurationOptions).GetDatabase(); + + multilevelCacheClient.Set(key, value); + CheckLifeCycle(database, key, 55, 60); + multilevelCacheClient.Remove(key); + } + [TestMethod] public void TestFormatCacheKeys() { diff --git a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/MultilevelCacheTest.cs b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/MultilevelCacheTest.cs index 7968f66b3..989d4d317 100644 --- a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/MultilevelCacheTest.cs +++ b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/MultilevelCacheTest.cs @@ -158,7 +158,7 @@ await File.WriteAllTextAsync(Path.Combine(rootPath, "appsettings.json"), VerifyOriginal(multilevelCacheClient as MultilevelCacheClient); VerifyTarget(serviceProvider.CreateScope().ServiceProvider.GetService()!.Create() as - MultilevelCacheClient); + MultilevelCacheClient); await File.WriteAllTextAsync(Path.Combine(rootPath, "appsettings.json"), oldContent); @@ -227,7 +227,6 @@ public void TestFormatCacheKeyByTypeNameAlias() multilevelCacheClient.Remove("configuration"); } - [TestMethod] public void TestFormatCacheKeyByTypeNameAlias2() { diff --git a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/TestBase.cs b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/TestBase.cs index 7016fb0fc..e58354617 100644 --- a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/TestBase.cs +++ b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/TestBase.cs @@ -19,4 +19,11 @@ protected static RedisConfigurationOptions RedisConfigurationOptions CacheKeyType = CacheKeyType.None } }; + + public static void CheckLifeCycle(IDatabase database, string key, double minVal, double maxVal) + { + var expireTimeSpan = database.KeyTimeToLive(key); + Assert.IsNotNull(expireTimeSpan); + Assert.IsTrue(expireTimeSpan.Value.TotalSeconds <= maxVal && expireTimeSpan.Value.TotalSeconds >= minVal); + } } diff --git a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/_Imports.cs b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/_Imports.cs index 43ef4ba12..077328362 100644 --- a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/_Imports.cs +++ b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/_Imports.cs @@ -7,8 +7,7 @@ global using Microsoft.AspNetCore.Builder; global using Microsoft.Extensions.Caching.Memory; global using Microsoft.Extensions.DependencyInjection; -global using Microsoft.Extensions.Options; global using Microsoft.VisualStudio.TestTools.UnitTesting; global using Moq; -global using NSubstitute; global using System.Reflection; +global using StackExchange.Redis; diff --git a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/appsettings.json b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/appsettings.json index 71950b8b4..85cb04686 100644 --- a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/appsettings.json +++ b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache.Tests/appsettings.json @@ -17,6 +17,7 @@ "Port": 6379 } ], - "DefaultDatabase": 3 + "DefaultDatabase": 3, + "AbsoluteExpirationRelativeToNow": "00:05:00" } } \ No newline at end of file diff --git a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache/MultilevelCacheClient.cs b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache/MultilevelCacheClient.cs index bdc7280a8..7313dc626 100644 --- a/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache/MultilevelCacheClient.cs +++ b/src/Contrib/Caching/Masa.Contrib.Caching.MultilevelCache/MultilevelCacheClient.cs @@ -174,7 +174,7 @@ public MultilevelCacheClient( MemoryCacheEntryOptions = memoryCacheEntryOptions }); - Pub(key, formattedKey, SubscribeOperation.Set, value, cacheEntry); + Pub(key, formattedKey, SubscribeOperation.Set, value, cacheEntry.CacheOptions); } return value; @@ -233,7 +233,7 @@ public MultilevelCacheClient( MemoryCacheEntryOptions = memoryCacheEntryOptions }); - await PubAsync(key, formattedKey, SubscribeOperation.Set, value, cacheEntry) + await PubAsync(key, formattedKey, SubscribeOperation.Set, value, cacheEntry.CacheOptions) .ConfigureAwait(false); }