CacheManager - Strongly typed caching with System.Runtime.Caching.MemoryCache - https://d-fens.ch/2017/03/02/nobrainer-strongly-typed-caching-with-system-runtime-caching-memorycache/
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
using System; | |
using System.Collections.Concurrent; | |
using System.Runtime.Caching; | |
namespace Net.Appclusive.Core.Cache | |
{ | |
public class CacheManagerBase | |
{ | |
protected const char CACHE_KEY_DELIMITER = '.'; | |
protected static readonly object _SyncRoot = new object(); | |
protected static readonly MemoryCache _MemoryCache = MemoryCache.Default; | |
protected static readonly ConcurrentDictionary<Type, ICacheManagerSettings> _Map = | |
new ConcurrentDictionary<Type, ICacheManagerSettings>(); | |
} | |
} |
using System.Diagnostics.Contracts; | |
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
using System.Reflection; | |
namespace Net.Appclusive.Core.Cache | |
{ | |
public abstract class CacheManagerSettingsAbsoluteExpirationBase : ICacheManagerSettingsAbsoluteExpiration | |
{ | |
private const string VIRTUAL_MEMBER_CALL_IN_CONSTRUCTOR = "You may only either override property ExpirationInSeconds or use protected .ctor(long expirationInSeconds)."; | |
private const BindingFlags BINDING_FLAGS = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy; | |
public bool IsSlidingExpiration { get; set; } = false; | |
public virtual long ExpirationInSeconds { get; set; } = long.MaxValue; | |
protected CacheManagerSettingsAbsoluteExpirationBase(long expirationInSeconds) | |
{ | |
var propertyInfo = this.GetType().GetProperty(nameof(ExpirationInSeconds), BINDING_FLAGS); | |
Contract.Assert(null != propertyInfo); | |
Contract.Assert(propertyInfo.DeclaringType == typeof(CacheManagerSettingsAbsoluteExpirationBase), VIRTUAL_MEMBER_CALL_IN_CONSTRUCTOR); | |
// ReSharper disable once VirtualMemberCallInConstructor | |
ExpirationInSeconds = expirationInSeconds; | |
} | |
protected CacheManagerSettingsAbsoluteExpirationBase() | |
{ | |
// N/A | |
} | |
} | |
} |
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
using System; | |
using System.Diagnostics.Contracts; | |
using System.Reflection; | |
using System.Runtime.Caching; | |
namespace Net.Appclusive.Core.Cache | |
{ | |
public abstract class CacheManagerSettingsSlidingExpirationBase : ICacheManagerSettingsSlidingExpiration | |
{ | |
private const string VIRTUAL_MEMBER_CALL_IN_CONSTRUCTOR = "You may only either override property CacheItemPolicy or use protected .ctor(long slidingExpirationInSeconds)."; | |
private const BindingFlags BINDING_FLAGS = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy; | |
protected CacheManagerSettingsSlidingExpirationBase(long slidingExpirationInSeconds) | |
{ | |
Contract.Requires(0 < slidingExpirationInSeconds); | |
var propertyInfo = this.GetType().GetProperty(nameof(CacheItemPolicy), BINDING_FLAGS); | |
Contract.Assert(null != propertyInfo); | |
Contract.Assert(propertyInfo.DeclaringType == typeof(CacheManagerSettingsSlidingExpirationBase), VIRTUAL_MEMBER_CALL_IN_CONSTRUCTOR); | |
// ReSharper disable once VirtualMemberCallInConstructor | |
CacheItemPolicy = new CacheItemPolicy | |
{ | |
SlidingExpiration = TimeSpan.FromSeconds(slidingExpirationInSeconds), | |
}; | |
} | |
protected CacheManagerSettingsSlidingExpirationBase() | |
{ | |
// N/A | |
} | |
public bool IsSlidingExpiration { get; set; } = true; | |
public virtual CacheItemPolicy CacheItemPolicy { get; set; } = new CacheItemPolicy | |
{ | |
SlidingExpiration = ObjectCache.NoSlidingExpiration, | |
}; | |
} | |
} |
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
using System; | |
using System.Diagnostics.Contracts; | |
using System.Runtime.Caching; | |
using System.Runtime.CompilerServices; | |
namespace Net.Appclusive.Core.Cache | |
{ | |
public class CacheManager<TSettings> : CacheManagerBase | |
where TSettings : ICacheManagerSettings | |
{ | |
// we want this lock only for the current generic class<T> | |
// ReSharper disable once StaticMemberInGenericType | |
private static readonly object _syncRoot = new object(); | |
protected CacheManager() | |
{ | |
// N/A | |
} | |
public static bool IsRegistered() | |
{ | |
return _Map.ContainsKey(typeof(TSettings)); | |
} | |
public static CacheManager<TSettings> GetInstance() | |
{ | |
if (_Map.ContainsKey(typeof(TSettings))) | |
{ | |
return new CacheManager<TSettings>(); | |
} | |
lock (_SyncRoot) | |
{ | |
if (_Map.ContainsKey(typeof(TSettings))) | |
{ | |
return new CacheManager<TSettings>(); | |
} | |
Contract.Assert(!typeof(TSettings).IsAbstract); | |
Contract.Assert(!typeof(TSettings).IsInterface); | |
var settings = IoC.IoC.DefaultContainer.GetInstance<TSettings>(); | |
Contract.Assert | |
( | |
settings is ICacheManagerSettingsAbsoluteExpiration | |
|| | |
settings is ICacheManagerSettingsSlidingExpiration | |
); | |
var isCacheSettingsTypeAddedToCache = _Map.TryAdd(typeof(TSettings), settings); | |
Contract.Assert(isCacheSettingsTypeAddedToCache, typeof(TSettings).FullName); | |
return new CacheManager<TSettings>(); | |
} | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
protected virtual string GetCacheKey<T>(string key) | |
{ | |
return string.Concat(typeof(TSettings).FullName, CACHE_KEY_DELIMITER, typeof(T).FullName, CACHE_KEY_DELIMITER, key); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
protected virtual string GetCacheKey<T>(long key) | |
{ | |
return string.Concat(typeof(TSettings).FullName, CACHE_KEY_DELIMITER, typeof(T).FullName, CACHE_KEY_DELIMITER, key); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
protected virtual string GetCacheKey<T>(Guid key) | |
{ | |
return string.Concat(typeof(TSettings).FullName, CACHE_KEY_DELIMITER, typeof(T).FullName, CACHE_KEY_DELIMITER, key); | |
} | |
public virtual T Get<T>(long id, bool useLock = false) | |
{ | |
return GetInternal<T>(GetCacheKey<T>(id), default(Func<T>), typeof(TSettings), useLock); | |
} | |
public virtual T Get<T>(long id, Func<T> valueFactory, bool useLock = false) | |
{ | |
return GetInternal(GetCacheKey<T>(id), valueFactory, typeof(TSettings), useLock); | |
} | |
public virtual T Get<T>(string key, bool useLock = false) | |
{ | |
Contract.Requires(!string.IsNullOrWhiteSpace(key)); | |
return GetInternal<T>(GetCacheKey<T>(key), default(Func<T>), typeof(TSettings), useLock); | |
} | |
public virtual T Get<T>(string key, Func<T> valueFactory, bool useLock = false) | |
{ | |
Contract.Requires(!string.IsNullOrWhiteSpace(key)); | |
return GetInternal(GetCacheKey<T>(key), valueFactory, typeof(TSettings), useLock); | |
} | |
public virtual T Get<T>(Guid key, bool useLock = false) | |
{ | |
return GetInternal<T>(GetCacheKey<T>(key), default(Func<T>), typeof(TSettings), useLock); | |
} | |
public virtual T Get<T>(Guid key, Func<T> valueFactory, bool useLock = false) | |
{ | |
return GetInternal(GetCacheKey<T>(key), valueFactory, typeof(TSettings), useLock); | |
} | |
public virtual T Get<T>(Type key, bool useLock = false) | |
{ | |
Contract.Requires(null != key); | |
return GetInternal(GetCacheKey<T>(key.FullName), default(Func<T>), typeof(TSettings), false); | |
} | |
public virtual T Get<T>(Type key, Func<T> valueFactory, bool useLock = false) | |
{ | |
Contract.Requires(null != key); | |
return GetInternal(GetCacheKey<T>(key.FullName), valueFactory, typeof(TSettings), useLock); | |
} | |
private static T GetInternal<T>(string cacheKey, Func<T> valueFactory, Type settingsType, bool useLock = false) | |
{ | |
if (null == valueFactory) | |
{ | |
return (T) _MemoryCache[cacheKey]; | |
} | |
T result; | |
Func<T> internaValueFactory = () => | |
{ | |
if (_MemoryCache.Contains(cacheKey)) | |
{ | |
return (T) _MemoryCache[cacheKey]; | |
} | |
var value = valueFactory(); | |
if (null == value) | |
{ | |
return default(T); | |
} | |
var settings = _Map[settingsType]; | |
if (settings.IsSlidingExpiration) | |
{ | |
var policy = ((ICacheManagerSettingsSlidingExpiration) settings).CacheItemPolicy; | |
_MemoryCache.Set(cacheKey, value, policy); | |
} | |
else | |
{ | |
var expirationInSeconds = ((ICacheManagerSettingsAbsoluteExpiration) settings).ExpirationInSeconds; | |
var expiration = long.MaxValue != expirationInSeconds | |
? DateTimeOffset.Now.AddSeconds(expirationInSeconds) | |
: ObjectCache.InfiniteAbsoluteExpiration; | |
_MemoryCache.Set(cacheKey, value, expiration); | |
} | |
return value; | |
}; | |
if (useLock) | |
{ | |
lock (_syncRoot) | |
{ | |
result = internaValueFactory(); | |
} | |
} | |
else | |
{ | |
result = internaValueFactory(); | |
} | |
return result; | |
} | |
public virtual void Set<T>(long key, T value) | |
{ | |
Contract.Requires(null != value); | |
SetInternal(GetCacheKey<T>(key), value, typeof(TSettings)); | |
} | |
public virtual void Set<T>(string key, T value) | |
{ | |
Contract.Requires(!string.IsNullOrWhiteSpace(key)); | |
Contract.Requires(null != value); | |
SetInternal(GetCacheKey<T>(key), value, typeof(TSettings)); | |
} | |
public virtual void Set<T>(Guid key, T value) | |
{ | |
Contract.Requires(null != value); | |
SetInternal(GetCacheKey<T>(key), value, typeof(TSettings)); | |
} | |
public virtual void Set<T>(Type key, T value) | |
{ | |
Contract.Requires(null != value); | |
SetInternal(GetCacheKey<T>(key.FullName), value, typeof(TSettings)); | |
} | |
private static void SetInternal<T>(string cacheKey, T value, Type settingsType) | |
{ | |
var settings = _Map[settingsType]; | |
if (settings.IsSlidingExpiration) | |
{ | |
var policy = ((ICacheManagerSettingsSlidingExpiration)settings).CacheItemPolicy; | |
_MemoryCache.Set(cacheKey, value, policy); | |
return; | |
} | |
var expirationInSeconds = ((ICacheManagerSettingsAbsoluteExpiration) settings).ExpirationInSeconds; | |
var expiration = long.MaxValue != expirationInSeconds | |
? DateTimeOffset.Now.AddSeconds(expirationInSeconds) | |
: ObjectCache.InfiniteAbsoluteExpiration; | |
_MemoryCache.Set(cacheKey, value, expiration); | |
} | |
public virtual T Remove<T>(long key) | |
{ | |
return RemoveInternal<T>(GetCacheKey<T>(key)); | |
} | |
public virtual T Remove<T>(string key) | |
{ | |
Contract.Requires(!string.IsNullOrWhiteSpace(key)); | |
return RemoveInternal<T>(GetCacheKey<T>(key)); | |
} | |
public virtual T Remove<T>(Guid key) | |
{ | |
return RemoveInternal<T>(GetCacheKey<T>(key)); | |
} | |
public virtual T Remove<T>(Type key) | |
{ | |
return RemoveInternal<T>(GetCacheKey<T>(key.FullName)); | |
} | |
private static T RemoveInternal<T>(string cacheKey) | |
{ | |
return (T) _MemoryCache.Remove(cacheKey); | |
} | |
} | |
} |
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
using System.Configuration; | |
using Net.Appclusive.Public.Constants; | |
namespace Net.Appclusive.Core.Cache | |
{ | |
public class CacheSettingsConfigurationSection | |
: ConfigurationSection | |
{ | |
//<configuration> | |
//<!-- Configuration section-handler declaration area. --> | |
// <configSections> | |
// <section | |
// name="cacheManagerSettingsConfiguration" | |
// type="Net.Appclusive.Core.Cache.CacheSettingsConfigurationSection, Net.Appclusive.Core" | |
// allowLocation="true" | |
// allowDefinition="Everywhere" | |
// /> | |
// <!-- Other <section> and <sectionGroup> elements. --> | |
// </configSections> | |
// <!-- Configuration section settings area. --> | |
// <cacheManagerSettingsConfiguration modelCacheManagerSettingsTimeout="60" /> | |
//</configuration> | |
[ConfigurationProperty(nameof(CacheSettings.defaultCacheManagerSettingsTimeout), DefaultValue = CacheSettings.defaultCacheManagerSettingsTimeout, IsRequired = false)] | |
public long DefaultCacheManagerSettingsTimeout | |
{ | |
get { return (long)this[nameof(CacheSettings.defaultCacheManagerSettingsTimeout)]; } | |
set { this[nameof(CacheSettings.defaultCacheManagerSettingsTimeout)] = value; } | |
} | |
[ConfigurationProperty(nameof(CacheSettings.modelCacheManagerSettingsTimeout), DefaultValue = CacheSettings.modelCacheManagerSettingsTimeout, IsRequired = false)] | |
public long ModelCacheManagerSettingsTimeout | |
{ | |
get { return (long)this[nameof(CacheSettings.modelCacheManagerSettingsTimeout)]; } | |
set { this[nameof(CacheSettings.modelCacheManagerSettingsTimeout)] = value; } | |
} | |
[ConfigurationProperty(nameof(CacheSettings.behaviourCacheManagerSettingsTimeout), DefaultValue = CacheSettings.behaviourCacheManagerSettingsTimeout, IsRequired = false)] | |
public long BehaviourCacheManagerSettingsTimeout | |
{ | |
get { return (long)this[nameof(CacheSettings.behaviourCacheManagerSettingsTimeout)]; } | |
set { this[nameof(CacheSettings.behaviourCacheManagerSettingsTimeout)] = value; } | |
} | |
[ConfigurationProperty(nameof(CacheSettings.tenantCacheManagerSettingsTimeout), DefaultValue = CacheSettings.tenantCacheManagerSettingsTimeout, IsRequired = false)] | |
public long TenantCacheManagerSettingsTimeout | |
{ | |
get { return (long)this[nameof(CacheSettings.tenantCacheManagerSettingsTimeout)]; } | |
set { this[nameof(CacheSettings.tenantCacheManagerSettingsTimeout)] = value; } | |
} | |
} | |
} |
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
namespace Net.Appclusive.Core.Cache | |
{ | |
public interface ICacheManagerSettings | |
{ | |
bool IsSlidingExpiration { get; set; } | |
} | |
} |
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
namespace Net.Appclusive.Core.Cache | |
{ | |
public interface ICacheManagerSettingsAbsoluteExpiration : ICacheManagerSettings | |
{ | |
long ExpirationInSeconds { get; set; } | |
} | |
} |
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
using System.Runtime.Caching; | |
namespace Net.Appclusive.Core.Cache | |
{ | |
public interface ICacheManagerSettingsSlidingExpiration : ICacheManagerSettings | |
{ | |
CacheItemPolicy CacheItemPolicy { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment