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.
Connected.Framework/Connected.Caching/StatefulCacheClient.cs

113 lines
2.6 KiB

2 years ago
using System.Collections.Immutable;
using System.Globalization;
using Connected.Interop;
using Connected.Threading;
namespace Connected.Caching;
public abstract class StatefulCacheClient<TEntry, TKey> : CacheClient<TEntry, TKey>, IStatefulCacheClient<TEntry, TKey> where TEntry : class
{
public event CacheInvalidateHandler Invalidate;
protected StatefulCacheClient(ICachingService cachingService, string key) : base(cachingService, key)
{
Locker = new AsyncLockerSlim();
CachingService.Invalidating += OnInvalidate;
}
private AsyncLockerSlim? Locker { get; set; }
protected virtual InvalidateBehavior InvalidateBehavior { get; } = InvalidateBehavior.KeepSameInstance;
private bool Initialized { get; set; }
private async void OnInvalidate(CacheEventArgs e)
{
if (string.Equals(e.Key, Key, StringComparison.OrdinalIgnoreCase))
{
if (Initialized)
await OnInvalidate(TypeConversion.Convert<TKey>(e.Id, CultureInfo.InvariantCulture));
Invalidate?.Invoke(e);
e.Behavior = InvalidateBehavior;
}
}
protected virtual async Task OnInvalidate(TKey id)
{
await Task.CompletedTask;
}
protected virtual async Task OnInitializing()
{
await Task.CompletedTask;
}
protected async Task Initialize()
{
if (Initialized || IsDisposed || Locker is null)
return;
await Locker.LockAsync(async () =>
{
if (Initialized || IsDisposed)
return;
await OnInitializing();
Initialized = true;
});
if (Initialized)
await OnInitialized();
}
protected virtual async Task OnInitialized()
{
await Task.CompletedTask;
}
protected override async Task<ImmutableList<TEntry>?> All()
{
await Initialize();
return base.All().Result;
}
protected override async Task<TEntry?> First()
{
await Initialize();
return await base.First();
}
protected override async Task<TEntry?> Get(Func<TEntry, bool> predicate)
{
await Initialize();
return await base.Get(predicate);
}
protected override async Task<TEntry?> Get(TKey id)
{
await Initialize();
return await base.Get(id);
}
protected override async Task<TEntry?> Get(TKey id, Func<EntryOptions, Task<TEntry>> retrieve)
{
await Initialize();
return await base.Get(id, retrieve);
}
protected override async Task<ImmutableList<TEntry>?> Where(Func<TEntry, bool> predicate)
{
await Initialize();
return await base.Where(predicate);
}
protected override void OnDisposing()
{
if (Locker is not null)
{
Locker?.Dispose();
Locker = null;
}
}
public override IEnumerator<TEntry> GetEnumerator()
{
AsyncUtils.RunSync(Initialize);
return base.GetEnumerator();
}
}