From 97267dec50b0d49ea65e1dc2320c1cd300a4ab05 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Mon, 1 Dec 2014 20:36:28 -0800 Subject: [PATCH 1/4] Improving caching API. This changeset cleans up Orchard.Caching by having the service accept and return plain objects to support both class and value types, while providing extension methods offering a strongly typed approach. Orchard.Redis is updated as the changes break any implementation of ICacheService and ICacheStorageProvider. --- .../Helpers/CachingExtensions.cs | 38 +++++++++++++++++++ .../Orchard.Caching/Orchard.Caching.csproj | 1 + .../Services/DefaultCacheService.cs | 8 ++-- .../Services/DefaultCacheStorageProvider.cs | 36 +++++++----------- .../Orchard.Caching/Services/ICacheService.cs | 34 ++--------------- .../Services/ICacheStorageProvider.cs | 6 +-- .../Caching/RedisCacheStorageProvider.cs | 8 ++-- 7 files changed, 66 insertions(+), 65 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs b/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs new file mode 100644 index 000000000..a5074654e --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs @@ -0,0 +1,38 @@ +using System; +using Orchard.Caching.Services; + +namespace Orchard.Caching.Helpers { + public static class CachingExtensions { + public static T Get(this ICacheStorageProvider provider, string key) { + return (T)provider.Get(key); + } + + public static T Get(this ICacheService cacheService, string key) { + return Get(cacheService, key, null); + } + + public static T Get(this ICacheService cacheService, string key, TimeSpan validFor) { + return Get(cacheService, key, null, validFor); + } + + public static T Get(this ICacheService cacheService, string key, Func factory) { + return Get(cacheService, key, factory, TimeSpan.MinValue); + } + + public static T Get(this ICacheService cacheService, string key, Func factory, TimeSpan validFor) { + var result = cacheService.Get(key); + + if (result == null && factory != null) { + var computed = factory(); + + if (validFor == TimeSpan.MinValue) + cacheService.Put(key, computed); + else + cacheService.Put(key, computed, validFor); + return computed; + } + + return (T)result; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj b/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj index e41ecf2ef..a2e9202fd 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj +++ b/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj @@ -75,6 +75,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs b/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs index db2f5a779..8e8a0da82 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs @@ -16,15 +16,15 @@ namespace Orchard.Caching.Services { _prefix = shellSettings.Name; } - public object Get(string key) { - return _cacheStorageProvider.Get(BuildFullKey(key)); + public object Get(string key) { + return _cacheStorageProvider.Get(BuildFullKey(key)); } - public void Put(string key, T value) { + public void Put(string key, object value) { _cacheStorageProvider.Put(BuildFullKey(key), value); } - public void Put(string key, T value, TimeSpan validFor) { + public void Put(string key, object value, TimeSpan validFor) { _cacheStorageProvider.Put(BuildFullKey(key), value, validFor); } diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheStorageProvider.cs index a9db8a565..e2e26fb22 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheStorageProvider.cs @@ -1,7 +1,6 @@ using System; using System.Globalization; using System.Runtime.Caching; -using Orchard.Environment.Configuration; using Orchard.Services; namespace Orchard.Caching.Services { @@ -10,22 +9,20 @@ namespace Orchard.Caching.Services { public class DefaultCacheStorageProvider : ICacheStorageProvider, ISingletonDependency { private event EventHandler Signaled; - private readonly ShellSettings _shellSettings; private readonly IClock _clock; // MemoryCache is optimal with one instance, see: http://stackoverflow.com/questions/8463962/using-multiple-instances-of-memorycache/13425322#13425322 private readonly MemoryCache _cache = MemoryCache.Default; - public DefaultCacheStorageProvider(ShellSettings shellSettings, IClock clock) { - _shellSettings = shellSettings; + public DefaultCacheStorageProvider(IClock clock) { _clock = clock; } - public void Put(string key, T value) { + public void Put(string key, object value) { // Keys are already prefixed by DefaultCacheService so no need to do it here again. - _cache.Set(key, value, GetCacheItemPolicy(MemoryCache.InfiniteAbsoluteExpiration)); + _cache.Set(key, value, GetCacheItemPolicy(ObjectCache.InfiniteAbsoluteExpiration)); } - public void Put(string key, T value, TimeSpan validFor) { + public void Put(string key, object value, TimeSpan validFor) { _cache.Set(key, value, GetCacheItemPolicy(new DateTimeOffset(_clock.UtcNow).ToOffset(validFor))); } @@ -39,23 +36,16 @@ namespace Orchard.Caching.Services { } } - public object Get(string key) { - var value = _cache.Get(key); - - // if the provided expression is non-null, and the provided object can - // be cast to the provided type without causing an exception to be thrown - if(value is T) { - return (T)value; - } - - return null; + public object Get(string key) { + return _cache.Get(key); } private CacheItemPolicy GetCacheItemPolicy(DateTimeOffset absoluteExpiration) { - var cacheItemPolicy = new CacheItemPolicy(); + var cacheItemPolicy = new CacheItemPolicy { + AbsoluteExpiration = absoluteExpiration, + SlidingExpiration = ObjectCache.NoSlidingExpiration + }; - cacheItemPolicy.AbsoluteExpiration = absoluteExpiration; - cacheItemPolicy.SlidingExpiration = MemoryCache.NoSlidingExpiration; cacheItemPolicy.ChangeMonitors.Add(new TenantCacheClearMonitor(this)); return cacheItemPolicy; @@ -72,17 +62,17 @@ namespace Orchard.Caching.Services { public TenantCacheClearMonitor(DefaultCacheStorageProvider storageProvider) { _storageProvider = storageProvider; _storageProvider.Signaled += OnSignalRaised; - base.InitializationComplete(); + InitializationComplete(); } protected override void Dispose(bool disposing) { - base.Dispose(); + Dispose(); _storageProvider.Signaled -= OnSignalRaised; } private void OnSignalRaised(object sender, EventArgs e) { // Cache objects are obligated to remove entry upon change notification. - base.OnChanged(null); + OnChanged(null); } } } diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs b/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs index f0437b4ec..f2ed9cd71 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs @@ -2,40 +2,12 @@ namespace Orchard.Caching.Services { public interface ICacheService : IDependency { - object Get(string key); + object Get(string key); - void Put(string key, T value); - void Put(string key, T value, TimeSpan validFor); + void Put(string key, object value); + void Put(string key, object value, TimeSpan validFor); void Remove(string key); void Clear(); } - - public static class CachingExtensions { - public static object Get(this ICacheService cacheService, string key, Func factory) { - var result = cacheService.Get(key); - - if (result == null) { - var computed = factory(); - cacheService.Put(key, computed); - return computed; - } - - // try to convert to T - return result; - } - - public static object Get(this ICacheService cacheService, string key, Func factory, TimeSpan validFor) { - var result = cacheService.Get(key); - - if (result == null) { - var computed = factory(); - cacheService.Put(key, computed, validFor); - return computed; - } - - // try to convert to T - return result; - } - } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheStorageProvider.cs index 4be4dc974..545b4f0df 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheStorageProvider.cs @@ -2,9 +2,9 @@ namespace Orchard.Caching.Services { public interface ICacheStorageProvider : IDependency { - object Get(string key); - void Put(string key, T value); - void Put(string key, T value, TimeSpan validFor); + object Get(string key); + void Put(string key, object value); + void Put(string key, object value, TimeSpan validFor); void Remove(string key); void Clear(); } diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs index 587d50a2e..8ec1c9a37 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs @@ -32,17 +32,17 @@ namespace Orchard.Redis.Caching { Logger = NullLogger.Instance; } - public object Get(string key) { + public object Get(string key) { var json = Database.StringGet(GetLocalizedKey(key)); - return JsonConvert.DeserializeObject(json); + return JsonConvert.DeserializeObject(json); } - public void Put(string key, T value) { + public void Put(string key, object value) { var json = JsonConvert.SerializeObject(value); Database.StringSet(GetLocalizedKey(key), json, null); } - public void Put(string key, T value, TimeSpan validFor) { + public void Put(string key, object value, TimeSpan validFor) { var json = JsonConvert.SerializeObject(value); Database.StringSet(GetLocalizedKey(key), json, validFor); } From 8e530cf82d62d6a004d4d2332262f38f98a76bfa Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 2 Dec 2014 13:20:09 -0800 Subject: [PATCH 2/4] Adding back argument for serialization purposes and updating extension methods to disambiguate between "object Get(string)" and "T Get(string)". --- .../Helpers/CachingExtensions.cs | 20 +++++++++---------- .../Modules/Orchard.Caching/Module.txt | 2 +- .../Services/DefaultCacheService.cs | 8 ++++---- .../Services/DefaultCacheStorageProvider.cs | 6 +++--- .../Orchard.Caching/Services/ICacheService.cs | 6 +++--- .../Services/ICacheStorageProvider.cs | 6 +++--- .../Caching/RedisCacheStorageProvider.cs | 8 ++++---- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs b/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs index a5074654e..d13bbeef0 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs @@ -3,24 +3,24 @@ using Orchard.Caching.Services; namespace Orchard.Caching.Helpers { public static class CachingExtensions { - public static T Get(this ICacheStorageProvider provider, string key) { - return (T)provider.Get(key); + public static T GetValue(this ICacheStorageProvider provider, string key) { + return (T)provider.Get(key); } - public static T Get(this ICacheService cacheService, string key) { - return Get(cacheService, key, null); + public static T GetValue(this ICacheService cacheService, string key) { + return GetValue(cacheService, key, null); } - public static T Get(this ICacheService cacheService, string key, TimeSpan validFor) { - return Get(cacheService, key, null, validFor); + public static T GetValue(this ICacheService cacheService, string key, TimeSpan validFor) { + return GetValue(cacheService, key, null, validFor); } - public static T Get(this ICacheService cacheService, string key, Func factory) { - return Get(cacheService, key, factory, TimeSpan.MinValue); + public static T GetValue(this ICacheService cacheService, string key, Func factory) { + return GetValue(cacheService, key, factory, TimeSpan.MinValue); } - public static T Get(this ICacheService cacheService, string key, Func factory, TimeSpan validFor) { - var result = cacheService.Get(key); + public static T GetValue(this ICacheService cacheService, string key, Func factory, TimeSpan validFor) { + var result = cacheService.Get(key); if (result == null && factory != null) { var computed = factory(); diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Module.txt b/src/Orchard.Web/Modules/Orchard.Caching/Module.txt index c047182af..cc209a36b 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Caching/Module.txt @@ -8,4 +8,4 @@ Description: Provides an API to cache business data. Features: Orchard.Caching: Description: Provides an API to cache business data. - Category: Performance \ No newline at end of file + Category: Performance \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs b/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs index 8e8a0da82..db2f5a779 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs @@ -16,15 +16,15 @@ namespace Orchard.Caching.Services { _prefix = shellSettings.Name; } - public object Get(string key) { - return _cacheStorageProvider.Get(BuildFullKey(key)); + public object Get(string key) { + return _cacheStorageProvider.Get(BuildFullKey(key)); } - public void Put(string key, object value) { + public void Put(string key, T value) { _cacheStorageProvider.Put(BuildFullKey(key), value); } - public void Put(string key, object value, TimeSpan validFor) { + public void Put(string key, T value, TimeSpan validFor) { _cacheStorageProvider.Put(BuildFullKey(key), value, validFor); } diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheStorageProvider.cs index e2e26fb22..5b576cc61 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheStorageProvider.cs @@ -17,12 +17,12 @@ namespace Orchard.Caching.Services { _clock = clock; } - public void Put(string key, object value) { + public void Put(string key, T value) { // Keys are already prefixed by DefaultCacheService so no need to do it here again. _cache.Set(key, value, GetCacheItemPolicy(ObjectCache.InfiniteAbsoluteExpiration)); } - public void Put(string key, object value, TimeSpan validFor) { + public void Put(string key, T value, TimeSpan validFor) { _cache.Set(key, value, GetCacheItemPolicy(new DateTimeOffset(_clock.UtcNow).ToOffset(validFor))); } @@ -36,7 +36,7 @@ namespace Orchard.Caching.Services { } } - public object Get(string key) { + public object Get(string key) { return _cache.Get(key); } diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs b/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs index f2ed9cd71..807a5fb63 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs @@ -2,10 +2,10 @@ namespace Orchard.Caching.Services { public interface ICacheService : IDependency { - object Get(string key); + object Get(string key); - void Put(string key, object value); - void Put(string key, object value, TimeSpan validFor); + void Put(string key, T value); + void Put(string key, T value, TimeSpan validFor); void Remove(string key); void Clear(); diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheStorageProvider.cs index 545b4f0df..4be4dc974 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheStorageProvider.cs @@ -2,9 +2,9 @@ namespace Orchard.Caching.Services { public interface ICacheStorageProvider : IDependency { - object Get(string key); - void Put(string key, object value); - void Put(string key, object value, TimeSpan validFor); + object Get(string key); + void Put(string key, T value); + void Put(string key, T value, TimeSpan validFor); void Remove(string key); void Clear(); } diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs index 8ec1c9a37..587d50a2e 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs @@ -32,17 +32,17 @@ namespace Orchard.Redis.Caching { Logger = NullLogger.Instance; } - public object Get(string key) { + public object Get(string key) { var json = Database.StringGet(GetLocalizedKey(key)); - return JsonConvert.DeserializeObject(json); + return JsonConvert.DeserializeObject(json); } - public void Put(string key, object value) { + public void Put(string key, T value) { var json = JsonConvert.SerializeObject(value); Database.StringSet(GetLocalizedKey(key), json, null); } - public void Put(string key, object value, TimeSpan validFor) { + public void Put(string key, T value, TimeSpan validFor) { var json = JsonConvert.SerializeObject(value); Database.StringSet(GetLocalizedKey(key), json, validFor); } From bf3bd93daa1570c66af331e6d08e06f568be61a5 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Sat, 21 Feb 2015 10:05:23 +0100 Subject: [PATCH 3/4] Applied Zoltan's suggestions (see comments on work item). Work Item: #21068 --- .../Helpers/CachingExtensions.cs | 25 +++++++++++-------- .../Services/DefaultCacheService.cs | 2 +- .../Orchard.Caching/Services/ICacheService.cs | 2 +- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs b/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs index d13bbeef0..39870f830 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs @@ -1,26 +1,31 @@ using System; using Orchard.Caching.Services; -namespace Orchard.Caching.Helpers { +// ReSharper disable once CheckNamespace +namespace Orchard.Caching { public static class CachingExtensions { - public static T GetValue(this ICacheStorageProvider provider, string key) { + public static T Get(this ICacheStorageProvider provider, string key) { return (T)provider.Get(key); } - public static T GetValue(this ICacheService cacheService, string key) { - return GetValue(cacheService, key, null); + public static object Get(this ICacheService cacheService, string key) { + return cacheService.Get(key); } - public static T GetValue(this ICacheService cacheService, string key, TimeSpan validFor) { - return GetValue(cacheService, key, null, validFor); + public static T Get(this ICacheService cacheService, string key) { + return Get(cacheService, key, null); } - public static T GetValue(this ICacheService cacheService, string key, Func factory) { - return GetValue(cacheService, key, factory, TimeSpan.MinValue); + public static T Get(this ICacheService cacheService, string key, TimeSpan validFor) { + return Get(cacheService, key, null, validFor); } - public static T GetValue(this ICacheService cacheService, string key, Func factory, TimeSpan validFor) { - var result = cacheService.Get(key); + public static T Get(this ICacheService cacheService, string key, Func factory) { + return Get(cacheService, key, factory, TimeSpan.MinValue); + } + + public static T Get(this ICacheService cacheService, string key, Func factory, TimeSpan validFor) { + var result = cacheService.GetObject(key); if (result == null && factory != null) { var computed = factory(); diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs b/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs index db2f5a779..367343c71 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Services/DefaultCacheService.cs @@ -16,7 +16,7 @@ namespace Orchard.Caching.Services { _prefix = shellSettings.Name; } - public object Get(string key) { + public object GetObject(string key) { return _cacheStorageProvider.Get(BuildFullKey(key)); } diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs b/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs index 807a5fb63..e305339c8 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Services/ICacheService.cs @@ -2,7 +2,7 @@ namespace Orchard.Caching.Services { public interface ICacheService : IDependency { - object Get(string key); + object GetObject(string key); void Put(string key, T value); void Put(string key, T value, TimeSpan validFor); From e84a1804125f51232bdf7dc39db20c0e54426fee Mon Sep 17 00:00:00 2001 From: Lombiq Date: Sat, 21 Feb 2015 15:24:01 +0100 Subject: [PATCH 4/4] Moving Orchard.Caching extension methods to the same namespace as the service they extend --- .../Modules/Orchard.Caching/Helpers/CachingExtensions.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs b/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs index 39870f830..d682aceea 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Helpers/CachingExtensions.cs @@ -1,8 +1,7 @@ using System; -using Orchard.Caching.Services; // ReSharper disable once CheckNamespace -namespace Orchard.Caching { +namespace Orchard.Caching.Services { public static class CachingExtensions { public static T Get(this ICacheStorageProvider provider, string key) { return (T)provider.Get(key);