mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
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.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using Orchard.Caching.Services;
|
||||
|
||||
namespace Orchard.Caching.Helpers {
|
||||
public static class CachingExtensions {
|
||||
public static T Get<T>(this ICacheStorageProvider provider, string key) {
|
||||
return (T)provider.Get(key);
|
||||
}
|
||||
|
||||
public static T Get<T>(this ICacheService cacheService, string key) {
|
||||
return Get<T>(cacheService, key, null);
|
||||
}
|
||||
|
||||
public static T Get<T>(this ICacheService cacheService, string key, TimeSpan validFor) {
|
||||
return Get<T>(cacheService, key, null, validFor);
|
||||
}
|
||||
|
||||
public static T Get<T>(this ICacheService cacheService, string key, Func<T> factory) {
|
||||
return Get(cacheService, key, factory, TimeSpan.MinValue);
|
||||
}
|
||||
|
||||
public static T Get<T>(this ICacheService cacheService, string key, Func<T> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Helpers\CachingExtensions.cs" />
|
||||
<Compile Include="Services\DefaultCacheService.cs" />
|
||||
<Compile Include="Services\DefaultCacheStorageProvider.cs" />
|
||||
<Compile Include="Services\ICacheService.cs" />
|
||||
|
||||
@@ -16,15 +16,15 @@ namespace Orchard.Caching.Services {
|
||||
_prefix = shellSettings.Name;
|
||||
}
|
||||
|
||||
public object Get<T>(string key) {
|
||||
return _cacheStorageProvider.Get<T>(BuildFullKey(key));
|
||||
public object Get(string key) {
|
||||
return _cacheStorageProvider.Get(BuildFullKey(key));
|
||||
}
|
||||
|
||||
public void Put<T>(string key, T value) {
|
||||
public void Put(string key, object value) {
|
||||
_cacheStorageProvider.Put(BuildFullKey(key), value);
|
||||
}
|
||||
|
||||
public void Put<T>(string key, T value, TimeSpan validFor) {
|
||||
public void Put(string key, object value, TimeSpan validFor) {
|
||||
_cacheStorageProvider.Put(BuildFullKey(key), value, validFor);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<T>(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<T>(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<T>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,40 +2,12 @@
|
||||
|
||||
namespace Orchard.Caching.Services {
|
||||
public interface ICacheService : IDependency {
|
||||
object Get<T>(string key);
|
||||
object Get(string key);
|
||||
|
||||
void Put<T>(string key, T value);
|
||||
void Put<T>(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<T>(this ICacheService cacheService, string key, Func<T> factory) {
|
||||
var result = cacheService.Get<T>(key);
|
||||
|
||||
if (result == null) {
|
||||
var computed = factory();
|
||||
cacheService.Put(key, computed);
|
||||
return computed;
|
||||
}
|
||||
|
||||
// try to convert to T
|
||||
return result;
|
||||
}
|
||||
|
||||
public static object Get<T>(this ICacheService cacheService, string key, Func<T> factory, TimeSpan validFor) {
|
||||
var result = cacheService.Get<T>(key);
|
||||
|
||||
if (result == null) {
|
||||
var computed = factory();
|
||||
cacheService.Put(key, computed, validFor);
|
||||
return computed;
|
||||
}
|
||||
|
||||
// try to convert to T
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace Orchard.Caching.Services {
|
||||
public interface ICacheStorageProvider : IDependency {
|
||||
object Get<T>(string key);
|
||||
void Put<T>(string key, T value);
|
||||
void Put<T>(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();
|
||||
}
|
||||
|
||||
@@ -32,17 +32,17 @@ namespace Orchard.Redis.Caching {
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public object Get<T>(string key) {
|
||||
public object Get(string key) {
|
||||
var json = Database.StringGet(GetLocalizedKey(key));
|
||||
return JsonConvert.DeserializeObject<T>(json);
|
||||
return JsonConvert.DeserializeObject(json);
|
||||
}
|
||||
|
||||
public void Put<T>(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<T>(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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user