add a central cache, for easy data retriveal

This commit is contained in:
TheXamlGuy
2024-01-14 20:35:38 +00:00
parent 1283e8ff58
commit 80f4d5a702
14 changed files with 154 additions and 122 deletions
@@ -9,22 +9,31 @@ namespace Hyperbar;
public static class IServiceCollectionExtensions
{
public static IServiceCollection AddCache<TKey, TValue>(this IServiceCollection services)
where TKey :
notnull
{
services.AddSingleton<ICache<TKey, TValue>, Cache<TKey, TValue>>();
services.AddTransient(provider => provider.GetService<ICache<TKey, TValue>>()!.Select(x => x.Value));
return services;
}
public static IServiceCollection AddCache<TValue>(this IServiceCollection services)
{
services.AddSingleton<ICache<TValue>, Cache<TValue>>();
services.AddTransient(provider => provider.GetService<ICache<TValue>>()!.Select(x => x));
return services;
}
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services)
where TConfiguration :
where TConfiguration :
class, new()
{
return services.AddConfiguration<TConfiguration>(typeof(TConfiguration).Name, "Settings.json", null);
}
public static IServiceCollection AddNotificationPipeline<TFromNotification, TToNotification>(this IServiceCollection services)
where TFromNotification :
INotification
where TToNotification :
INotification, new()
{
return services.AddHandler<NotficationPipelineHandler<TFromNotification, TToNotification>>();
}
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services,
TConfiguration? defaults = null)
where TConfiguration :
@@ -65,12 +74,12 @@ public static class IServiceCollectionExtensions
serializerDelegate.Invoke(defaultSerializer);
}
return new ConfigurationReader<TConfiguration>(provider.GetRequiredService<IConfigurationSource<TConfiguration>>(),
return new ConfigurationReader<TConfiguration>(provider.GetRequiredService<IConfigurationSource<TConfiguration>>(),
defaultSerializer);
});
services.AddSingleton<IConfigurationWriter<TConfiguration>>(provider =>
{
{
JsonSerializerOptions? defaultSerializer = null;
if (serializerDelegate is not null)
{
@@ -78,7 +87,7 @@ public static class IServiceCollectionExtensions
serializerDelegate.Invoke(defaultSerializer);
}
return new ConfigurationWriter<TConfiguration>(provider.GetRequiredService<IConfigurationSource<TConfiguration>>(),
return new ConfigurationWriter<TConfiguration>(provider.GetRequiredService<IConfigurationSource<TConfiguration>>(),
defaultSerializer);
});
@@ -115,7 +124,7 @@ public static class IServiceCollectionExtensions
}
public static IServiceCollection AddHandler<THandler>(this IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Transient)
ServiceLifetime lifetime = ServiceLifetime.Transient)
where THandler :
IHandler
{
@@ -134,31 +143,40 @@ public static class IServiceCollectionExtensions
provider => provider.GetRequiredService<THandler>(), lifetime));
}
}
}
}
if (contract.Name == typeof(IHandler<,>).Name)
{
if (contract.GetGenericArguments() is { Length: 2 } arguments)
{
Type requestType = arguments[0];
Type responseType = arguments[1];
if (typeof(THandler).GetInterface(typeof(IHandler<,>).Name) is { } requestContract)
{
if (requestContract.GetGenericArguments() is { Length: 2 } arguments)
{
Type requestType = arguments[0];
Type responseType = arguments[1];
Type wrapperType = typeof(RequestClassHandlerWrapper<,>).MakeGenericType(requestType, responseType);
Type wrapperType = typeof(RequestClassHandlerWrapper<,>).MakeGenericType(requestType, responseType);
services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime));
services.Add(new ServiceDescriptor(wrapperType,
provider => provider.GetService<IServiceFactory>()?.Create(wrapperType,
provider.GetRequiredService<THandler>(),
provider.GetServices(typeof(IPipelineBehavior<,>).MakeGenericType(requestType, responseType)))!,
lifetime
));
services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime));
services.Add(new ServiceDescriptor(wrapperType,
provider => provider.GetService<IServiceFactory>()?.Create(wrapperType,
provider.GetRequiredService<THandler>(),
provider.GetServices(typeof(IPipelineBehavior<,>).MakeGenericType(requestType, responseType)))!,
lifetime
));
}
}
}
}
return services;
}
public static IServiceCollection AddNotificationPipeline<TFromNotification, TToNotification>(this IServiceCollection services)
where TFromNotification :
INotification
where TToNotification :
INotification, new()
{
return services.AddHandler<NotficationPipelineHandler<TFromNotification, TToNotification>>();
}
public static IServiceCollection AddWidgetTemplate<TWidgetContent>(this IServiceCollection services)
where TWidgetContent :
IWidgetViewModel
+36 -51
View File
@@ -1,83 +1,68 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Collections.Concurrent;
using System.Reactive.Disposables;
namespace Hyperbar;
public class Cache<TKey, TService>(IDisposer disposer) :
ICache<TKey, TService>
where TKey : notnull
public class Cache<TValue>(IDisposer disposer) :
ICache<TValue>
{
private readonly IDictionary<TKey, TService> cache = new Dictionary<TKey, TService>();
private readonly List<TValue> cache = [];
public TService this[TKey key]
public void Add(TValue value)
{
get => cache[key];
set => cache[key] = value;
disposer.Add(value!, Disposable.Create(() =>
{
Remove(value);
}));
cache.Add(value);
}
public ICollection<TKey> Keys => cache.Keys;
public void Clear() => cache.Clear();
public ICollection<TService> Values => cache.Values;
public IEnumerator<TValue> GetEnumerator() => cache.GetEnumerator();
public int Count => cache.Count;
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public bool IsReadOnly => false;
public bool Remove(TValue value) => cache.Remove(value);
}
public void Add(TKey key, TService value)
public class Cache<TKey, TValue>(IDisposer disposer) :
ICache<TKey, TValue>
where TKey : notnull
{
private readonly ConcurrentDictionary<TKey, TValue> cache = new();
public void Add(TKey key,
TValue value)
{
disposer.Add(value!, Disposable.Create(() =>
{
Remove(key);
}));
cache.Add(key, value);
}
public void Add(KeyValuePair<TKey, TService> item)
{
cache.Add(item);
cache.TryAdd(key, value);
}
public void Clear() => cache.Clear();
public bool Contains(KeyValuePair<TKey, TService> item)
{
return cache.Contains(item);
}
public bool ContainsKey(TKey key) => cache.ContainsKey(key);
public bool ContainsKey(TKey key)
{
return cache.ContainsKey(key);
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => cache.GetEnumerator();
public void CopyTo(KeyValuePair<TKey, TService>[] array, int arrayIndex)
{
cache.CopyTo(array, arrayIndex);
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<KeyValuePair<TKey, TService>> GetEnumerator()
{
return cache.GetEnumerator();
}
public bool Remove(TKey key) => cache.Remove(key, out _);
public bool Remove(TKey key)
public bool TryGetValue(TKey key, out TValue? value)
{
return cache.Remove(key);
}
if (cache.TryGetValue(key, out value))
{
return true;
}
public bool Remove(KeyValuePair<TKey, TService> item)
{
return cache.Remove(item);
}
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TService value)
{
return cache.TryGetValue(key, out value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return cache.GetEnumerator();
value = default;
return false;
}
}
+24 -3
View File
@@ -1,8 +1,29 @@
namespace Hyperbar;
using Microsoft.Extensions.DependencyInjection;
public interface ICache<TKey, TViewModel> :
IDictionary<TKey, TViewModel>
namespace Hyperbar;
public interface ICache<TValue> :
IEnumerable<TValue>
{
void Add(TValue value);
void Clear();
bool Remove(TValue value);
}
public interface ICache<TKey, TValue> :
IEnumerable<KeyValuePair<TKey, TValue>>
where TKey : notnull
{
void Add(TKey key,
TValue value);
void Clear();
bool ContainsKey(TKey key);
bool Remove(TKey key);
bool TryGetValue(TKey key, out TValue? value);
}
+2 -3
View File
@@ -1,10 +1,9 @@
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
namespace Hyperbar;
public class ServiceScopeFactory<TService>(IServiceScopeFactory serviceScopeFactory,
ConcurrentDictionary<TService, IServiceScope> services) :
ICache<TService, IServiceScope> cache) :
IServiceScopeFactory<TService>
where TService : notnull
{
@@ -16,7 +15,7 @@ public class ServiceScopeFactory<TService>(IServiceScopeFactory serviceScopeFact
{
if (serviceFactory.Create<TService>(parameters) is TService service)
{
services.TryAdd(service, serviceScope);
cache.Add(service, serviceScope);
return service;
}
}
+2 -3
View File
@@ -1,16 +1,15 @@
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
namespace Hyperbar;
public class ServiceScopeProvider<TService>(ConcurrentDictionary<TService, IServiceScope> services) :
public class ServiceScopeProvider<TService>(ICache<TService, IServiceScope> cache) :
IServiceScopeProvider<TService>
where TService : notnull
{
public bool TryGet(TService service,
out IServiceScope? serviceScope)
{
if (services.TryGetValue(service, out IServiceScope? value))
if (cache.TryGetValue(service, out IServiceScope? value))
{
serviceScope = value;
return true;
+10 -5
View File
@@ -1,16 +1,23 @@
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using System.Reactive.Concurrency;
namespace Hyperbar;
public class Mediator(IServiceProvider provider) :
public interface IDispatcher
{
Task InvokeAsync(Action action);
}
public class Mediator(IServiceProvider provider,
IDispatcher dispatcher) :
IMediator
{
private readonly SynchronizationContext? context = SynchronizationContext.Current;
private readonly ConcurrentDictionary<Type, List<dynamic>> subjects = [];
public ValueTask PublishAsync<TNotification>(TNotification notification,
public async ValueTask PublishAsync<TNotification>(TNotification notification,
CancellationToken cancellationToken = default)
where TNotification :
INotification
@@ -31,10 +38,8 @@ public class Mediator(IServiceProvider provider) :
foreach (INotificationHandler<TNotification> handler in handlers)
{
context?.Post(async state => await handler.Handle(notification, cancellationToken), null);
await dispatcher.InvokeAsync(async () => await handler.Handle(notification, cancellationToken));
}
return ValueTask.CompletedTask;
}
public ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> request,
@@ -283,6 +283,7 @@ public partial class ObservableCollectionViewModel<TItem> :
return true;
}
void IList.Remove(object? value)
{
if (IsCompatibleObject(value))