@ -1,4 +1,5 @@
using System ;
using System.Linq ;
using System.Threading ;
using System.Threading.Tasks ;
using Microsoft.Extensions.Caching.Distributed ;
@ -15,10 +16,36 @@ namespace Volo.Abp.Caching
/// Represents a distributed cache of <typeparamref name="TCacheItem" /> type.
/// </summary>
/// <typeparam name="TCacheItem">The type of cache item being cached.</typeparam>
public class DistributedCache < TCacheItem > : IDistributedCache < TCacheItem >
public class DistributedCache < TCacheItem > : DistributedCache < TCacheItem , string > , IDistributedCache < TCacheItem >
where TCacheItem : class
{
public ILogger < DistributedCache < TCacheItem > > Logger { get ; set ; }
public DistributedCache (
IOptions < CacheOptions > cacheOption ,
IOptions < DistributedCacheOptions > distributedCacheOption ,
IDistributedCache cache ,
ICancellationTokenProvider cancellationTokenProvider ,
IDistributedCacheSerializer serializer ,
ICurrentTenant currentTenant ) : base (
cacheOption : cacheOption ,
distributedCacheOption : distributedCacheOption ,
cache : cache ,
cancellationTokenProvider : cancellationTokenProvider ,
serializer : serializer ,
currentTenant : currentTenant )
{
}
}
/// <summary>
/// Represents a distributed cache of <typeparamref name="TCacheItem" /> type.
/// Uses a generic cache key type of <typeparamref name="TCacheKey" /> type.
/// </summary>
/// <typeparam name="TCacheItem">The type of cache item being cached.</typeparam>
/// <typeparam name="TCacheKey">The type of cache key being used.</typeparam>
public class DistributedCache < TCacheItem , TCacheKey > : IDistributedCache < TCacheItem , TCacheKey >
where TCacheItem : class
{
public ILogger < DistributedCache < TCacheItem , TCacheKey > > Logger { get ; set ; }
protected string CacheName { get ; set ; }
@ -52,7 +79,7 @@ namespace Volo.Abp.Caching
_ cacheOption = cacheOption . Value ;
Cache = cache ;
CancellationTokenProvider = cancellationTokenProvider ;
Logger = NullLogger < DistributedCache < TCacheItem > > . Instance ;
Logger = NullLogger < DistributedCache < TCacheItem , TCacheKey > > . Instance ;
Serializer = serializer ;
CurrentTenant = currentTenant ;
@ -60,7 +87,60 @@ namespace Volo.Abp.Caching
SetDefaultOptions ( ) ;
}
protected virtual string NormalizeKey ( TCacheKey key )
{
Type type = key . GetType ( ) ;
string keyValue = key . ToString ( ) ;
// If complex type of object, override the key value with property concatenation
if ( ! typeof ( IComparable ) . IsAssignableFrom ( type ) | | type . IsPrimitive | | type . IsValueType )
{
var sb = new System . Text . StringBuilder ( ) ;
var properties = type . GetProperties ( ) . Where ( prop = > prop . CanRead & & prop . CanWrite ) ;
foreach ( var prop in properties )
{
var value = prop . GetValue ( key , null ) ;
if ( value ! = null )
{
sb . Append ( value . ToString ( ) ) ;
}
}
keyValue = sb . ToString ( ) ;
}
var normalizedKey = "c:" + CacheName + ",k:" + _ cacheOption . KeyPrefix + keyValue ;
if ( ! IgnoreMultiTenancy & & CurrentTenant . Id . HasValue )
{
normalizedKey = "t:" + CurrentTenant . Id . Value + "," + normalizedKey ;
}
return normalizedKey ;
}
protected virtual DistributedCacheEntryOptions GetDefaultCacheEntryOptions ( )
{
foreach ( var configure in _ cacheOption . CacheConfigurators )
{
var options = configure . Invoke ( CacheName ) ;
if ( options ! = null )
{
return options ;
}
}
return _ cacheOption . GlobalCacheEntryOptions ;
}
protected virtual void SetDefaultOptions ( )
{
CacheName = CacheNameAttribute . GetCacheName ( typeof ( TCacheItem ) ) ;
//IgnoreMultiTenancy
IgnoreMultiTenancy = typeof ( TCacheItem ) . IsDefined ( typeof ( IgnoreMultiTenancyAttribute ) , true ) ;
//Configure default cache entry options
DefaultCacheOptions = GetDefaultCacheEntryOptions ( ) ;
}
/// <summary>
/// Gets a cache item with the given key. If no cache item is found for the given key then returns null.
/// </summary>
@ -68,7 +148,7 @@ namespace Volo.Abp.Caching
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
/// <returns>The cache item, or null.</returns>
public virtual TCacheItem Get (
string key ,
TCacheKey key ,
bool? hideErrors = null )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
@ -106,7 +186,7 @@ namespace Volo.Abp.Caching
/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
/// <returns>The cache item, or null.</returns>
public virtual async Task < TCacheItem > GetAsync (
string key ,
TCacheKey key ,
bool? hideErrors = null ,
CancellationToken token = default )
{
@ -131,7 +211,7 @@ namespace Volo.Abp.Caching
throw ;
}
if ( cachedBytes = = null )
{
return null ;
@ -139,7 +219,6 @@ namespace Volo.Abp.Caching
return Serializer . Deserialize < TCacheItem > ( cachedBytes ) ;
}
/// <summary>
/// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item
/// provided by <paramref name="factory" /> delegate and returns the provided cache item.
@ -149,10 +228,10 @@ namespace Volo.Abp.Caching
/// <param name="optionsFactory">The cache options for the factory delegate.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
/// <returns>The cache item.</returns>
public TCacheItem GetOrAdd (
string key ,
Func < TCacheItem > factory ,
Func < DistributedCacheEntryOptions > optionsFactory = null ,
public virtual TCacheItem GetOrAdd (
TCacheKey key ,
Func < TCacheItem > factory ,
Func < DistributedCacheEntryOptions > optionsFactory = null ,
bool? hideErrors = null )
{
var value = Get ( key , hideErrors ) ;
@ -175,7 +254,6 @@ namespace Volo.Abp.Caching
return value ;
}
/// <summary>
/// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item
/// provided by <paramref name="factory" /> delegate and returns the provided cache item.
@ -186,11 +264,11 @@ namespace Volo.Abp.Caching
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
/// <returns>The cache item.</returns>
public async Task < TCacheItem > GetOrAddAsync (
string key ,
Func < Task < TCacheItem > > factory ,
Func < DistributedCacheEntryOptions > optionsFactory = null ,
bool? hideErrors = null ,
public virtual async Task < TCacheItem > GetOrAddAsync (
TCacheKey key ,
Func < Task < TCacheItem > > factory ,
Func < DistributedCacheEntryOptions > optionsFactory = null ,
bool? hideErrors = null ,
CancellationToken token = default )
{
token = CancellationTokenProvider . FallbackToProvider ( token ) ;
@ -214,7 +292,6 @@ namespace Volo.Abp.Caching
return value ;
}
/// <summary>
/// Sets the cache item value for the provided key.
/// </summary>
@ -223,7 +300,7 @@ namespace Volo.Abp.Caching
/// <param name="options">The cache options for the value.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
public virtual void Set (
string key ,
TCacheKey key ,
TCacheItem value ,
DistributedCacheEntryOptions options = null ,
bool? hideErrors = null )
@ -249,7 +326,6 @@ namespace Volo.Abp.Caching
throw ;
}
}
/// <summary>
/// Sets the cache item value for the provided key.
/// </summary>
@ -260,7 +336,7 @@ namespace Volo.Abp.Caching
/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
public virtual async Task SetAsync (
string key ,
TCacheKey key ,
TCacheItem value ,
DistributedCacheEntryOptions options = null ,
bool? hideErrors = null ,
@ -288,15 +364,14 @@ namespace Volo.Abp.Caching
throw ;
}
}
/// <summary>
/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
/// </summary>
/// <param name="key">The key of cached item to be retrieved from the cache.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
public virtual void Refresh (
string key ,
bool? hideErrors = null )
TCacheKey key , bool?
hideErrors = null )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
@ -315,7 +390,6 @@ namespace Volo.Abp.Caching
throw ;
}
}
/// <summary>
/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
/// </summary>
@ -324,7 +398,7 @@ namespace Volo.Abp.Caching
/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
public virtual async Task RefreshAsync (
string key ,
TCacheKey key ,
bool? hideErrors = null ,
CancellationToken token = default )
{
@ -345,15 +419,13 @@ namespace Volo.Abp.Caching
throw ;
}
}
/// <summary>
/// Removes the cache item for given key from cache.
/// </summary>
/// <param name="key">The key of cached item to be retrieved from the cache.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
public virtual void Remove (
string key ,
TCacheKey key ,
bool? hideErrors = null )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
@ -372,7 +444,6 @@ namespace Volo.Abp.Caching
throw ;
}
}
/// <summary>
/// Removes the cache item for given key from cache.
/// </summary>
@ -381,7 +452,7 @@ namespace Volo.Abp.Caching
/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
public virtual async Task RemoveAsync (
string key ,
TCacheKey key ,
bool? hideErrors = null ,
CancellationToken token = default )
{
@ -402,364 +473,7 @@ namespace Volo.Abp.Caching
throw ;
}
}
protected virtual string NormalizeKey ( string key )
{
var normalizedKey = "c:" + CacheName + ",k:" + _ cacheOption . KeyPrefix + key ;
if ( ! IgnoreMultiTenancy & & CurrentTenant . Id . HasValue )
{
normalizedKey = "t:" + CurrentTenant . Id . Value + "," + normalizedKey ;
}
return normalizedKey ;
}
protected virtual DistributedCacheEntryOptions GetDefaultCacheEntryOptions ( )
{
foreach ( var configure in _ cacheOption . CacheConfigurators )
{
var options = configure . Invoke ( CacheName ) ;
if ( options ! = null )
{
return options ;
}
}
return _ cacheOption . GlobalCacheEntryOptions ;
}
protected virtual void SetDefaultOptions ( )
{
CacheName = CacheNameAttribute . GetCacheName ( typeof ( TCacheItem ) ) ;
//IgnoreMultiTenancy
IgnoreMultiTenancy = typeof ( TCacheItem ) . IsDefined ( typeof ( IgnoreMultiTenancyAttribute ) , true ) ;
//Configure default cache entry options
DefaultCacheOptions = GetDefaultCacheEntryOptions ( ) ;
}
}
/// <summary>
/// Represents a distributed cache of <typeparamref name="TCacheItem" /> type.
/// Uses a generic cache key type of <typeparamref name="TCacheKey" /> type.
/// </summary>
/// <typeparam name="TCacheItem">The type of cache item being cached.</typeparam>
/// <typeparam name="TCacheKey">The type of cache key being used.</typeparam>
public class DistributedCache < TCacheItem , TCacheKey > : IDistributedCache < TCacheItem , TCacheKey >
where TCacheItem : class
{
public ILogger < DistributedCache < TCacheItem , TCacheKey > > Logger { get ; set ; }
protected string CacheName { get ; set ; }
protected bool IgnoreMultiTenancy { get ; set ; }
protected IDistributedCache Cache { get ; }
protected ICancellationTokenProvider CancellationTokenProvider { get ; }
protected IDistributedCacheSerializer Serializer { get ; }
protected ICurrentTenant CurrentTenant { get ; }
protected SemaphoreSlim SyncSemaphore { get ; }
protected DistributedCacheEntryOptions DefaultCacheOptions ;
private readonly CacheOptions _ cacheOption ;
private readonly DistributedCacheOptions _d istributedCacheOption ;
public DistributedCache (
IOptions < CacheOptions > cacheOption ,
IOptions < DistributedCacheOptions > distributedCacheOption ,
IDistributedCache cache ,
ICancellationTokenProvider cancellationTokenProvider ,
IDistributedCacheSerializer serializer ,
ICurrentTenant currentTenant )
{
_d istributedCacheOption = distributedCacheOption . Value ;
_ cacheOption = cacheOption . Value ;
Cache = cache ;
CancellationTokenProvider = cancellationTokenProvider ;
Logger = NullLogger < DistributedCache < TCacheItem , TCacheKey > > . Instance ;
Serializer = serializer ;
CurrentTenant = currentTenant ;
SyncSemaphore = new SemaphoreSlim ( 1 , 1 ) ;
SetDefaultOptions ( ) ;
}
protected virtual string NormalizeKey ( string key )
{
var normalizedKey = "c:" + CacheName + ",k:" + _ cacheOption . KeyPrefix + key ;
if ( ! IgnoreMultiTenancy & & CurrentTenant . Id . HasValue )
{
normalizedKey = "t:" + CurrentTenant . Id . Value + "," + normalizedKey ;
}
return normalizedKey ;
}
protected virtual DistributedCacheEntryOptions GetDefaultCacheEntryOptions ( )
{
foreach ( var configure in _ cacheOption . CacheConfigurators )
{
var options = configure . Invoke ( CacheName ) ;
if ( options ! = null )
{
return options ;
}
}
return _ cacheOption . GlobalCacheEntryOptions ;
}
protected virtual void SetDefaultOptions ( )
{
CacheName = CacheNameAttribute . GetCacheName ( typeof ( TCacheItem ) ) ;
//IgnoreMultiTenancy
IgnoreMultiTenancy = typeof ( TCacheItem ) . IsDefined ( typeof ( IgnoreMultiTenancyAttribute ) , true ) ;
//Configure default cache entry options
DefaultCacheOptions = GetDefaultCacheEntryOptions ( ) ;
}
public virtual TCacheItem Get ( TCacheKey key , bool? hideErrors = null )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
byte [ ] cachedBytes ;
try
{
cachedBytes = Cache . Get ( NormalizeKey ( key ? . ToString ( ) ) ) ;
}
catch ( Exception ex )
{
if ( hideErrors = = true )
{
Logger . LogException ( ex , LogLevel . Warning ) ;
return null ;
}
throw ;
}
if ( cachedBytes = = null )
{
return null ;
}
return Serializer . Deserialize < TCacheItem > ( cachedBytes ) ;
}
public virtual async Task < TCacheItem > GetAsync ( TCacheKey key , bool? hideErrors = null , CancellationToken token = default )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
byte [ ] cachedBytes ;
try
{
cachedBytes = await Cache . GetAsync (
NormalizeKey ( key . ToString ( ) ) ,
CancellationTokenProvider . FallbackToProvider ( token )
) ;
}
catch ( Exception ex )
{
if ( hideErrors = = true )
{
Logger . LogException ( ex , LogLevel . Warning ) ;
return null ;
}
throw ;
}
if ( cachedBytes = = null )
{
return null ;
}
return Serializer . Deserialize < TCacheItem > ( cachedBytes ) ;
}
public virtual TCacheItem GetOrAdd ( TCacheKey key , Func < TCacheItem > factory , Func < DistributedCacheEntryOptions > optionsFactory = null , bool? hideErrors = null )
{
var value = Get ( key , hideErrors ) ;
if ( value ! = null )
{
return value ;
}
using ( SyncSemaphore . Lock ( ) )
{
value = Get ( key , hideErrors ) ;
if ( value ! = null )
{
return value ;
}
value = factory ( ) ;
Set ( key , value , optionsFactory ? . Invoke ( ) , hideErrors ) ;
}
return value ;
}
public virtual async Task < TCacheItem > GetOrAddAsync ( TCacheKey key , Func < Task < TCacheItem > > factory , Func < DistributedCacheEntryOptions > optionsFactory = null , bool? hideErrors = null , CancellationToken token = default )
{
token = CancellationTokenProvider . FallbackToProvider ( token ) ;
var value = await GetAsync ( key , hideErrors , token ) ;
if ( value ! = null )
{
return value ;
}
using ( await SyncSemaphore . LockAsync ( token ) )
{
value = await GetAsync ( key , hideErrors , token ) ;
if ( value ! = null )
{
return value ;
}
value = await factory ( ) ;
await SetAsync ( key , value , optionsFactory ? . Invoke ( ) , hideErrors , token ) ;
}
return value ;
}
public virtual void Set ( TCacheKey key , TCacheItem value , DistributedCacheEntryOptions options = null , bool? hideErrors = null )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
try
{
Cache . Set (
NormalizeKey ( key . ToString ( ) ) ,
Serializer . Serialize ( value ) ,
options ? ? DefaultCacheOptions
) ;
}
catch ( Exception ex )
{
if ( hideErrors = = true )
{
Logger . LogException ( ex , LogLevel . Warning ) ;
return ;
}
throw ;
}
}
public virtual async Task SetAsync ( TCacheKey key , TCacheItem value , DistributedCacheEntryOptions options = null , bool? hideErrors = null , CancellationToken token = default )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
try
{
await Cache . SetAsync (
NormalizeKey ( key . ToString ( ) ) ,
Serializer . Serialize ( value ) ,
options ? ? DefaultCacheOptions ,
CancellationTokenProvider . FallbackToProvider ( token )
) ;
}
catch ( Exception ex )
{
if ( hideErrors = = true )
{
Logger . LogException ( ex , LogLevel . Warning ) ;
return ;
}
throw ;
}
}
public virtual void Refresh ( TCacheKey key , bool? hideErrors = null )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
try
{
Cache . Refresh ( NormalizeKey ( key . ToString ( ) ) ) ;
}
catch ( Exception ex )
{
if ( hideErrors = = true )
{
Logger . LogException ( ex , LogLevel . Warning ) ;
return ;
}
throw ;
}
}
public virtual async Task RefreshAsync ( TCacheKey key , bool? hideErrors = null , CancellationToken token = default )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
try
{
await Cache . RefreshAsync ( NormalizeKey ( key . ToString ( ) ) , CancellationTokenProvider . FallbackToProvider ( token ) ) ;
}
catch ( Exception ex )
{
if ( hideErrors = = true )
{
Logger . LogException ( ex , LogLevel . Warning ) ;
return ;
}
throw ;
}
}
public virtual void Remove ( TCacheKey key , bool? hideErrors = null )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
try
{
Cache . Remove ( NormalizeKey ( key . ToString ( ) ) ) ;
}
catch ( Exception ex )
{
if ( hideErrors = = true )
{
Logger . LogException ( ex , LogLevel . Warning ) ;
}
throw ;
}
}
public virtual async Task RemoveAsync ( TCacheKey key , bool? hideErrors = null , CancellationToken token = default )
{
hideErrors = hideErrors ? ? _d istributedCacheOption . HideErrors ;
try
{
await Cache . RemoveAsync ( NormalizeKey ( key . ToString ( ) ) , CancellationTokenProvider . FallbackToProvider ( token ) ) ;
}
catch ( Exception ex )
{
if ( hideErrors = = true )
{
Logger . LogException ( ex , LogLevel . Warning ) ;
return ;
}
throw ;
}
}
}
}