Created
March 3, 2017 07:32
-
-
Save dfch/5623b1f9dd36a13b40696f6928f42c72 to your computer and use it in GitHub Desktop.
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/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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>(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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, | |
}; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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; } | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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