mirror of https://github.com/abpframework/abp.git
csharpabpc-sharpframeworkblazoraspnet-coredotnet-coreaspnetcorearchitecturesaasdomain-driven-designangularmulti-tenancy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
338 lines
10 KiB
338 lines
10 KiB
using System;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Caching.Distributed;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Microsoft.Extensions.Options;
|
|
using Nito.AsyncEx;
|
|
using Volo.Abp.MultiTenancy;
|
|
using Volo.Abp.Serialization;
|
|
using Volo.Abp.Threading;
|
|
|
|
namespace Volo.Abp.Caching
|
|
{
|
|
public class DistributedCache<TCacheItem> : IDistributedCache<TCacheItem>
|
|
where TCacheItem : class
|
|
{
|
|
public ILogger<DistributedCache<TCacheItem>> Logger { get; set; }
|
|
|
|
protected string CacheName { get; set; }
|
|
|
|
protected bool IgnoreMultiTenancy { get; set; }
|
|
|
|
protected IDistributedCache Cache { get; }
|
|
|
|
protected ICancellationTokenProvider CancellationTokenProvider { get; }
|
|
|
|
protected IObjectSerializer ObjectSerializer { get; }
|
|
|
|
protected ICurrentTenant CurrentTenant { get; }
|
|
|
|
protected AsyncLock AsyncLock { get; } = new AsyncLock();
|
|
|
|
protected DistributedCacheEntryOptions DefaultCacheOptions;
|
|
|
|
private readonly CacheOptions _cacheOption;
|
|
|
|
private readonly DistributedCacheOptions _distributedCacheOption;
|
|
|
|
public DistributedCache(
|
|
IOptions<CacheOptions> cacheOption,
|
|
IOptions<DistributedCacheOptions> distributedCacheOption,
|
|
IDistributedCache cache,
|
|
ICancellationTokenProvider cancellationTokenProvider,
|
|
|
|
IObjectSerializer objectSerializer,
|
|
ICurrentTenant currentTenant)
|
|
{
|
|
_distributedCacheOption = distributedCacheOption.Value;
|
|
_cacheOption = cacheOption.Value;
|
|
Cache = cache;
|
|
CancellationTokenProvider = cancellationTokenProvider;
|
|
Logger = NullLogger<DistributedCache<TCacheItem>>.Instance;
|
|
ObjectSerializer = objectSerializer;
|
|
CurrentTenant = currentTenant;
|
|
|
|
SetDefaultOptions();
|
|
}
|
|
|
|
public virtual TCacheItem Get(string key, bool? hideErrors = null)
|
|
{
|
|
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
|
|
|
|
byte[] cachedBytes;
|
|
|
|
try
|
|
{
|
|
cachedBytes = Cache.Get(NormalizeKey(key));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if ((bool) hideErrors)
|
|
{
|
|
Logger.LogException(ex, LogLevel.Warning);
|
|
return null;
|
|
}
|
|
throw;
|
|
}
|
|
|
|
if (cachedBytes == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return ObjectSerializer.Deserialize<TCacheItem>(cachedBytes);
|
|
}
|
|
|
|
public virtual async Task<TCacheItem> GetAsync(string key, bool? hideErrors = null, CancellationToken token = default)
|
|
{
|
|
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
|
|
|
|
byte[] cachedBytes;
|
|
|
|
try
|
|
{
|
|
cachedBytes = await Cache.GetAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if ((bool)hideErrors)
|
|
{
|
|
Logger.LogException(ex, LogLevel.Warning);
|
|
return null;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
|
|
if (cachedBytes == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return ObjectSerializer.Deserialize<TCacheItem>(cachedBytes);
|
|
}
|
|
|
|
public TCacheItem GetOrAdd(
|
|
string key,
|
|
Func<TCacheItem> factory,
|
|
Func<DistributedCacheEntryOptions> optionsFactory = null,
|
|
bool? hideErrors = null)
|
|
{
|
|
var value = Get(key, hideErrors);
|
|
if (value != null)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
using (AsyncLock.Lock())
|
|
{
|
|
value = Get(key, hideErrors);
|
|
if (value != null)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
value = factory();
|
|
Set(key, value, optionsFactory?.Invoke(), hideErrors);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
public async Task<TCacheItem> GetOrAddAsync(
|
|
string 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 AsyncLock.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(string key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null)
|
|
{
|
|
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
|
|
|
|
try
|
|
{
|
|
Cache.Set(
|
|
NormalizeKey(key),
|
|
ObjectSerializer.Serialize(value),
|
|
options ?? DefaultCacheOptions
|
|
);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if ((bool) hideErrors)
|
|
{
|
|
Logger.LogException(ex, LogLevel.Warning);
|
|
return;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public virtual async Task SetAsync(string key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null, CancellationToken token = default)
|
|
{
|
|
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
|
|
|
|
try
|
|
{
|
|
await Cache.SetAsync(
|
|
NormalizeKey(key),
|
|
ObjectSerializer.Serialize(value),
|
|
options ?? DefaultCacheOptions,
|
|
CancellationTokenProvider.FallbackToProvider(token)
|
|
);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if ((bool)hideErrors)
|
|
{
|
|
Logger.LogException(ex, LogLevel.Warning);
|
|
return;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public virtual void Refresh(string key, bool? hideErrors = null)
|
|
{
|
|
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
|
|
|
|
try
|
|
{
|
|
Cache.Refresh(NormalizeKey(key));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if ((bool) hideErrors)
|
|
{
|
|
Logger.LogException(ex, LogLevel.Warning);
|
|
return;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public virtual async Task RefreshAsync(string key, bool? hideErrors = null, CancellationToken token = default)
|
|
{
|
|
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
|
|
|
|
try
|
|
{
|
|
await Cache.RefreshAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if ((bool)hideErrors)
|
|
{
|
|
Logger.LogException(ex, LogLevel.Warning);
|
|
return;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public virtual void Remove(string key, bool? hideErrors = null)
|
|
{
|
|
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
|
|
|
|
try
|
|
{
|
|
Cache.Remove(NormalizeKey(key));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if ((bool) hideErrors)
|
|
{
|
|
Logger.LogException(ex, LogLevel.Warning);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public virtual async Task RemoveAsync(string key, bool? hideErrors = null, CancellationToken token = default)
|
|
{
|
|
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
|
|
|
|
try
|
|
{
|
|
await Cache.RemoveAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if ((bool)hideErrors)
|
|
{
|
|
Logger.LogException(ex, LogLevel.Warning);
|
|
return;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
protected virtual string NormalizeKey(string key)
|
|
{
|
|
var normalizedKey = "c:" + CacheName + ",k:" + 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();
|
|
}
|
|
}
|
|
}
|