diff --git a/src/EasyCaching.Core/DefaultEasyCachingKeyGenerator.cs b/src/EasyCaching.Core/DefaultEasyCachingKeyGenerator.cs index cbfee6fb..8e4d1762 100644 --- a/src/EasyCaching.Core/DefaultEasyCachingKeyGenerator.cs +++ b/src/EasyCaching.Core/DefaultEasyCachingKeyGenerator.cs @@ -44,6 +44,38 @@ public string GetCacheKey(MethodInfo methodInfo, object[] args, string prefix) } } + /// + /// Gets the cache key prefix. + /// + /// The cache key prefix. + /// Method info. + /// Prefix. + public string GetCacheKeyPrefix(MethodInfo methodInfo, string prefix) + { + if (string.IsNullOrWhiteSpace(prefix)) + { + var typeName = methodInfo.DeclaringType.Name; + var methodName = methodInfo.Name; + + return this.GenerateCacheKeyPrefix(typeName, methodName); + } + else + { + return this.GenerateCacheKeyPrefix(string.Empty, prefix); + } + } + + /// + /// Generates the cache key prefix. + /// + /// The cache key prefix. + /// First. + /// Second. + private string GenerateCacheKeyPrefix(string first, string second) + { + return string.Concat(first,_linkChar,second,_linkChar).TrimStart(_linkChar); + } + /// /// Formats the arguments to part of cache key. /// @@ -72,11 +104,7 @@ private string GenerateCacheKey(string typeName, string methodName, IList diff --git a/src/EasyCaching.Core/IEasyCachingKeyGenerator.cs b/src/EasyCaching.Core/IEasyCachingKeyGenerator.cs index 2c96eb4d..ed454970 100644 --- a/src/EasyCaching.Core/IEasyCachingKeyGenerator.cs +++ b/src/EasyCaching.Core/IEasyCachingKeyGenerator.cs @@ -7,7 +7,6 @@ /// public interface IEasyCachingKeyGenerator { - /// /// Gets the cache key. /// @@ -16,5 +15,13 @@ public interface IEasyCachingKeyGenerator /// Arguments. /// Prefix. string GetCacheKey(MethodInfo methodInfo, object[] args, string prefix); + + /// + /// Gets the cache key prefix. + /// + /// The cache key prefix. + /// Method info. + /// Prefix. + string GetCacheKeyPrefix(MethodInfo methodInfo, string prefix); } } diff --git a/src/EasyCaching.Core/Internal/EasyCachingInterceptorAttribute.cs b/src/EasyCaching.Core/Internal/EasyCachingInterceptorAttribute.cs index 314b31d2..e660a6b7 100644 --- a/src/EasyCaching.Core/Internal/EasyCachingInterceptorAttribute.cs +++ b/src/EasyCaching.Core/Internal/EasyCachingInterceptorAttribute.cs @@ -54,10 +54,13 @@ public class EasyCachingPutAttribute : EasyCachingInterceptorAttribute public class EasyCachingEvictAttribute : EasyCachingInterceptorAttribute { /// - /// Gets or sets a value indicating whether evict all cached values which are + /// Gets or sets a value indicating whether evict all cached values by cachekey prefix /// - /// true if all; otherwise, false. - public bool All { get; set; } = false; + /// + /// This need to use with CacheKeyPrefix. + /// + /// true if is all; otherwise, false. + public bool IsAll { get; set; } = false; /// /// Gets or sets a value indicating whether is before. diff --git a/src/EasyCaching.Interceptor.AspectCore/EasyCachingInterceptor.cs b/src/EasyCaching.Interceptor.AspectCore/EasyCachingInterceptor.cs index ea8cbc4a..1644690c 100644 --- a/src/EasyCaching.Interceptor.AspectCore/EasyCachingInterceptor.cs +++ b/src/EasyCaching.Interceptor.AspectCore/EasyCachingInterceptor.cs @@ -72,7 +72,7 @@ private async Task ProceedAbleAsync(AspectContext context, AspectDelegate next) // Invoke the method if we don't have a cache hit await next(context); - if (!string.IsNullOrWhiteSpace(cacheKey)) + if (!string.IsNullOrWhiteSpace(cacheKey) && context.ReturnValue != null) await CacheProvider.SetAsync(cacheKey, context.ReturnValue, TimeSpan.FromSeconds(attribute.Expiration)); } } @@ -92,7 +92,7 @@ private async Task ProcessPutAsync(AspectContext context) { var attribute = context.ServiceMethod.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(EasyCachingPutAttribute)) as EasyCachingPutAttribute; - if (attribute != null) + if (attribute != null && context.ReturnValue != null) { var cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters,attribute.CacheKeyPrefix); @@ -111,11 +111,22 @@ private async Task ProcessEvictAsync(AspectContext context, bool isBefore) var attribute = context.ServiceMethod.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(EasyCachingEvictAttribute)) as EasyCachingEvictAttribute; if (attribute != null && attribute.IsBefore == isBefore) - { - var cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix); + { + if(attribute.IsAll) + { + //If is all , clear all cached items which cachekey start with the prefix. + var cachePrefix = KeyGenerator.GetCacheKeyPrefix(context.ServiceMethod, attribute.CacheKeyPrefix); - await CacheProvider.RemoveAsync(cacheKey); + await CacheProvider.RemoveByPrefixAsync(cachePrefix); + } + else + { + //If not all , just remove the cached item by its cachekey. + var cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix); + + await CacheProvider.RemoveAsync(cacheKey); + } } } } -} \ No newline at end of file +} diff --git a/src/EasyCaching.Interceptor.Castle/EasyCachingInterceptor.cs b/src/EasyCaching.Interceptor.Castle/EasyCachingInterceptor.cs index 4657ca84..9ff3fb9a 100644 --- a/src/EasyCaching.Interceptor.Castle/EasyCachingInterceptor.cs +++ b/src/EasyCaching.Interceptor.Castle/EasyCachingInterceptor.cs @@ -77,7 +77,7 @@ private void ProceedAble(IInvocation invocation) // Invoke the method if we don't have a cache hit invocation.Proceed(); - if (!string.IsNullOrWhiteSpace(cacheKey)) + if (!string.IsNullOrWhiteSpace(cacheKey) && invocation.ReturnValue != null) _cacheProvider.Set(cacheKey, invocation.ReturnValue, TimeSpan.FromSeconds(attribute.Expiration)); } } @@ -98,7 +98,7 @@ private void ProcessPut(IInvocation invocation) var attribute = serviceMethod.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(EasyCachingPutAttribute)) as EasyCachingPutAttribute; - if (attribute != null) + if (attribute != null && invocation.ReturnValue != null) { var cacheKey = _keyGenerator.GetCacheKey(serviceMethod, invocation.Arguments, attribute.CacheKeyPrefix); @@ -118,10 +118,21 @@ private void ProcessEvict(IInvocation invocation, bool isBefore) var attribute = serviceMethod.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(EasyCachingEvictAttribute)) as EasyCachingEvictAttribute; if (attribute != null && attribute.IsBefore == isBefore) - { - var cacheKey = _keyGenerator.GetCacheKey(serviceMethod, invocation.Arguments, attribute.CacheKeyPrefix); + { + if(attribute.IsAll) + { + //If is all , clear all cached items which cachekey start with the prefix. + var cacheKeyPrefix = _keyGenerator.GetCacheKeyPrefix(serviceMethod, attribute.CacheKeyPrefix); - _cacheProvider.Remove(cacheKey); + _cacheProvider.RemoveByPrefix(cacheKeyPrefix); + } + else + { + //If not all , just remove the cached item by its cachekey. + var cacheKey = _keyGenerator.GetCacheKey(serviceMethod, invocation.Arguments, attribute.CacheKeyPrefix); + + _cacheProvider.Remove(cacheKey); + } } } } diff --git a/test/EasyCaching.UnitTests/Core/DefaultEasyCachingKeyGeneratorTest.cs b/test/EasyCaching.UnitTests/Core/DefaultEasyCachingKeyGeneratorTest.cs index b8034c54..0035e43e 100644 --- a/test/EasyCaching.UnitTests/Core/DefaultEasyCachingKeyGeneratorTest.cs +++ b/test/EasyCaching.UnitTests/Core/DefaultEasyCachingKeyGeneratorTest.cs @@ -23,11 +23,9 @@ public void Generate_CacheKey_With_No_Params_Method_Should_Succeed() var methodName = "Method1"; MethodInfo methodInfo = typeof(Demo).GetMethod(methodName); - var key = _keyGenerator.GetCacheKey(methodInfo, new object[]{} ,string.Empty); + var key = _keyGenerator.GetCacheKey(methodInfo, new object[] { }, string.Empty); - var keyBeforeHash = $"Demo:Method1:0"; - - Assert.Equal(SHA1AndBase64(keyBeforeHash),key); + Assert.Equal($"Demo:Method1:0", key); } [Fact] @@ -38,9 +36,7 @@ public void Generate_CacheKey_With_No_Params_And_Prefix_Method_Should_Succeed() var key = _keyGenerator.GetCacheKey(methodInfo, new object[] { }, "GenKey"); - var keyBeforeHash = $"GenKey:0"; - - Assert.Equal(SHA1AndBase64(keyBeforeHash), key); + Assert.Equal($"GenKey:0", key); } [Fact] @@ -49,11 +45,9 @@ public void Generate_CacheKey_With_Int_Param_Method_Should_Succeed() var methodName = "Method2"; MethodInfo methodInfo = typeof(Demo).GetMethod(methodName); - var key = _keyGenerator.GetCacheKey(methodInfo, new object[] { 10 } ,string.Empty); - - var keyBeforeHash = $"Demo:Method2:10"; + var key = _keyGenerator.GetCacheKey(methodInfo, new object[] { 10 }, string.Empty); - Assert.Equal(SHA1AndBase64(keyBeforeHash), key); + Assert.Equal($"Demo:Method2:10", key); } [Fact] @@ -64,9 +58,7 @@ public void Generate_CacheKey_With_Int_Param_And_Prefix_Method_Should_Succeed() var key = _keyGenerator.GetCacheKey(methodInfo, new object[] { 10 }, "GenKey"); - var keyBeforeHash = $"GenKey:10"; - - Assert.Equal(SHA1AndBase64(keyBeforeHash), key); + Assert.Equal($"GenKey:10", key); } [Fact] @@ -75,11 +67,9 @@ public void Generate_CacheKey_With_String_Param_Method_Should_Succeed() var methodName = "Method3"; MethodInfo methodInfo = typeof(Demo).GetMethod(methodName); - var key = _keyGenerator.GetCacheKey(methodInfo, new object[]{ "str" } ,string.Empty); - - var keyBeforeHash = $"Demo:Method3:str"; + var key = _keyGenerator.GetCacheKey(methodInfo, new object[] { "str" }, string.Empty); - Assert.Equal(SHA1AndBase64(keyBeforeHash), key); + Assert.Equal($"Demo:Method3:str", key); } [Fact] @@ -90,9 +80,7 @@ public void Generate_CacheKey_With_String_Param_And_Prefix_Method_Should_Succeed var key = _keyGenerator.GetCacheKey(methodInfo, new object[] { "str" }, "GenKey"); - var keyBeforeHash = $"GenKey:str"; - - Assert.Equal(SHA1AndBase64(keyBeforeHash), key); + Assert.Equal($"GenKey:str", key); } [Fact] @@ -103,9 +91,7 @@ public void Generate_CacheKey_With_DateTime_Param_Method_Should_Succeed() var key = _keyGenerator.GetCacheKey(methodInfo, null, string.Empty); - var keyBeforeHash = $"Demo:Method4:0"; - - Assert.Equal(SHA1AndBase64(keyBeforeHash), key); + Assert.Equal($"Demo:Method4:0", key); } [Fact] @@ -116,9 +102,7 @@ public void Generate_CacheKey_With_DateTime_Param_And_Prefix_Method_Should_Succe var key = _keyGenerator.GetCacheKey(methodInfo, null, "GenKey"); - var keyBeforeHash = $"GenKey:0"; - - Assert.Equal(SHA1AndBase64(keyBeforeHash), key); + Assert.Equal($"GenKey:0", key); } [Fact] @@ -129,9 +113,7 @@ public void Generate_CacheKey_With_ICachable_Param_Method_Should_Succeed() var key = _keyGenerator.GetCacheKey(methodInfo, new object[] { new Product() }, string.Empty); - var keyBeforeHash = $"Demo:Method5:1000"; - - Assert.Equal(SHA1AndBase64(keyBeforeHash), key); + Assert.Equal($"Demo:Method5:1000", key); } [Fact] @@ -142,9 +124,29 @@ public void Generate_CacheKey_With_ICachable_Param_And_Prefix_Method_Should_Succ var key = _keyGenerator.GetCacheKey(methodInfo, new object[] { new Product() }, "GenKey"); - var keyBeforeHash = $"GenKey:1000"; + Assert.Equal($"GenKey:1000", key); + } + + [Fact] + public void Generate_CacheKeyPrefix_Without_PrefixParam_Should_Succeed() + { + var methodName = "Method3"; + MethodInfo methodInfo = typeof(Demo).GetMethod(methodName); + + var key = _keyGenerator.GetCacheKeyPrefix(methodInfo, string.Empty); + + Assert.Equal($"Demo:Method3:", key); + } + + [Fact] + public void Generate_CacheKeyPrefix_With_PrefixParam_Should_Succeed() + { + var methodName = "Method3"; + MethodInfo methodInfo = typeof(Demo).GetMethod(methodName); + + var key = _keyGenerator.GetCacheKeyPrefix(methodInfo, "prefix"); - Assert.Equal(SHA1AndBase64(keyBeforeHash), key); + Assert.Equal($"prefix:", key); } private string SHA1AndBase64(string str) @@ -173,4 +175,4 @@ public class Product : ICachable } } -} +} \ No newline at end of file diff --git a/test/EasyCaching.UnitTests/Infrastructure/IExampleService.cs b/test/EasyCaching.UnitTests/Infrastructure/IExampleService.cs index 4992a1c9..7aad8dce 100644 --- a/test/EasyCaching.UnitTests/Infrastructure/IExampleService.cs +++ b/test/EasyCaching.UnitTests/Infrastructure/IExampleService.cs @@ -12,10 +12,18 @@ public interface ICastleExampleService string PutTest(int num,string str = "123"); string EvictTest(); + + string EvictAllTest(); } public class CastleExampleService : ICastleExampleService, IEasyCaching { + [EasyCachingEvict(CacheKeyPrefix = "CastleExample",IsAll = true)] + public string EvictAllTest() + { + return "EvictAllTest"; + } + [EasyCachingEvict(CacheKeyPrefix = "CastleExample")] public string EvictTest() { @@ -50,12 +58,20 @@ public interface IAspectCoreExampleService : IEasyCaching [EasyCachingEvict(CacheKeyPrefix = "AspectCoreExample")] string EvictTest(); + [EasyCachingEvict(CacheKeyPrefix = "AspectCoreExample",IsAll = true)] + string EvictAllTest(); + [EasyCachingPut(CacheKeyPrefix = "AspectCoreExample")] string PutTest(int num , string str="123"); } public class AspectCoreExampleService : IAspectCoreExampleService { + public string EvictAllTest() + { + return "EvictAllTest"; + } + public string EvictTest() { return "EvictTest"; diff --git a/test/EasyCaching.UnitTests/InterceptorTests/AspectCoreInterceptorTest.cs b/test/EasyCaching.UnitTests/InterceptorTests/AspectCoreInterceptorTest.cs index 749cb471..ea0d6b46 100755 --- a/test/EasyCaching.UnitTests/InterceptorTests/AspectCoreInterceptorTest.cs +++ b/test/EasyCaching.UnitTests/InterceptorTests/AspectCoreInterceptorTest.cs @@ -102,5 +102,30 @@ public void Evict_Should_Succeed() Assert.False(after.HasValue); } + [Fact] + public void EvictAll_Should_Succeed() + { + System.Reflection.MethodInfo method = typeof(AspectCoreExampleService).GetMethod("EvictAllTest"); + + var prefix = _keyGenerator.GetCacheKeyPrefix(method, "AspectCoreExample"); + + _cachingProvider.Set(string.Concat(prefix, "1"), "AAA", TimeSpan.FromSeconds(30)); + _cachingProvider.Set(string.Concat(prefix, "2"), "AAA", TimeSpan.FromSeconds(30)); + + var value1 = _cachingProvider.Get(string.Concat(prefix, "1")); + var value2 = _cachingProvider.Get(string.Concat(prefix, "2")); + + Assert.Equal("AAA", value1.Value); + Assert.Equal("AAA", value2.Value); + + _service.EvictAllTest(); + + var after1 = _cachingProvider.Get(string.Concat(prefix, "1")); + var after2 = _cachingProvider.Get(string.Concat(prefix, "2")); + + Assert.False(after1.HasValue); + Assert.False(after2.HasValue); + } + } } \ No newline at end of file diff --git a/test/EasyCaching.UnitTests/InterceptorTests/CastleInterceptorTest.cs b/test/EasyCaching.UnitTests/InterceptorTests/CastleInterceptorTest.cs index fe5840c6..e7649018 100755 --- a/test/EasyCaching.UnitTests/InterceptorTests/CastleInterceptorTest.cs +++ b/test/EasyCaching.UnitTests/InterceptorTests/CastleInterceptorTest.cs @@ -103,5 +103,30 @@ public void Evict_Should_Succeed() Assert.False(after.HasValue); } + + [Fact] + public void EvictAll_Should_Succeed() + { + System.Reflection.MethodInfo method = typeof(AspectCoreExampleService).GetMethod("EvictAllTest"); + + var prefix = _keyGenerator.GetCacheKeyPrefix(method, "CastleExample"); + + _cachingProvider.Set(string.Concat(prefix, "1"), "AAA", TimeSpan.FromSeconds(30)); + _cachingProvider.Set(string.Concat(prefix, "2"), "AAA", TimeSpan.FromSeconds(30)); + + var value1 = _cachingProvider.Get(string.Concat(prefix, "1")); + var value2 = _cachingProvider.Get(string.Concat(prefix, "2")); + + Assert.Equal("AAA", value1.Value); + Assert.Equal("AAA", value2.Value); + + _service.EvictAllTest(); + + var after1 = _cachingProvider.Get(string.Concat(prefix, "1")); + var after2 = _cachingProvider.Get(string.Concat(prefix, "2")); + + Assert.False(after1.HasValue); + Assert.False(after2.HasValue); + } } } \ No newline at end of file