threading fixes
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public record ConfigurationChanged<TConfiguration>(TConfiguration Configuration) : INotification
|
||||
where TConfiguration :
|
||||
class;
|
||||
@@ -1,13 +1,7 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public record ConfigurationChanged<TConfiguration>(TConfiguration Configuration) : INotification
|
||||
where TConfiguration :
|
||||
class;
|
||||
|
||||
public class ConfigurationInitializer<TConfiguration>(DefaultConfiguration<TConfiguration> defaults,
|
||||
IConfigurationWriter<TConfiguration> writer,
|
||||
IOptionsMonitor<TConfiguration> options,
|
||||
@@ -17,12 +11,16 @@ public class ConfigurationInitializer<TConfiguration>(DefaultConfiguration<TConf
|
||||
{
|
||||
public Task InitializeAsync()
|
||||
{
|
||||
options.OnChange(args =>
|
||||
options.OnChange(async args =>
|
||||
{
|
||||
mediator.PublishAsync(new ConfigurationChanged<TConfiguration>(args));
|
||||
await mediator.PublishAsync(new ConfigurationChanged<TConfiguration>(args));
|
||||
});
|
||||
|
||||
writer.Write(defaults.Configuration);
|
||||
if (defaults.Configuration is not null)
|
||||
{
|
||||
writer.Write(defaults.Configuration);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public class DefaultConfiguration<TConfiguration>(TConfiguration configuration)
|
||||
public class DefaultConfiguration<TConfiguration>(TConfiguration? configuration = null)
|
||||
where TConfiguration :
|
||||
class
|
||||
{
|
||||
public TConfiguration Configuration => configuration;
|
||||
public TConfiguration? Configuration => configuration;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public static class IServiceCollectionExtensions
|
||||
{
|
||||
Type notificationType = arguments[0];
|
||||
|
||||
services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), ServiceLifetime.Singleton));
|
||||
services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime));
|
||||
services.Add(new ServiceDescriptor(typeof(INotificationHandler<>).MakeGenericType(notificationType),
|
||||
provider => provider.GetRequiredService<THandler>(), lifetime));
|
||||
}
|
||||
@@ -53,13 +53,24 @@ public static class IServiceCollectionExtensions
|
||||
Type responseType = arguments[1];
|
||||
|
||||
services.AddTransient(typeof(THandler));
|
||||
services.AddTransient(responseType, provider => ((dynamic)provider.GetRequiredService<THandler>()).Map());
|
||||
services.AddTransient(responseType, provider =>
|
||||
{
|
||||
return ((dynamic)provider.GetRequiredService<THandler>()).Handle();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services,
|
||||
IConfiguration configuration)
|
||||
where TConfiguration :
|
||||
class, new()
|
||||
{
|
||||
return services.AddConfiguration<TConfiguration>(configuration, typeof(TConfiguration).Name, "Settings.json", null);
|
||||
}
|
||||
|
||||
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services,
|
||||
IConfiguration configuration,
|
||||
TConfiguration? defaults = null)
|
||||
@@ -107,10 +118,11 @@ public static class IServiceCollectionExtensions
|
||||
|
||||
if (defaults is not null)
|
||||
{
|
||||
services.AddTransient(provider => new DefaultConfiguration<TConfiguration>(defaults));
|
||||
services.AddTransient<IInitializer, ConfigurationInitializer<TConfiguration>>();
|
||||
}
|
||||
|
||||
services.AddTransient(provider => new DefaultConfiguration<TConfiguration>(defaults));
|
||||
services.AddTransient<IInitializer, ConfigurationInitializer<TConfiguration>>();
|
||||
|
||||
services.AddTransient<IWritableConfiguration<TConfiguration>, WritableConfiguration<TConfiguration>>();
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
public interface IMappingHandler<TFrom, TTo> : IHandler
|
||||
{
|
||||
TTo Map();
|
||||
TTo Handle();
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface INotificationHandler<in TNotification>
|
||||
public interface INotificationHandler<in TNotification> :
|
||||
IHandler
|
||||
where TNotification :
|
||||
INotification
|
||||
{
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace Hyperbar;
|
||||
public class Mediator(IServiceProvider provider) :
|
||||
IMediator
|
||||
{
|
||||
private readonly ConditionalWeakTable<Type, dynamic> handlers = [];
|
||||
private readonly ConditionalWeakTable<Type, dynamic> addedHandlers = [];
|
||||
|
||||
public ValueTask PublishAsync<TNotification>(TNotification notification,
|
||||
public async ValueTask PublishAsync<TNotification>(TNotification notification,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TNotification :
|
||||
INotification
|
||||
@@ -16,7 +16,7 @@ public class Mediator(IServiceProvider provider) :
|
||||
List<INotificationHandler<TNotification>> handlers =
|
||||
provider.GetServices<INotificationHandler<TNotification>>().ToList();
|
||||
|
||||
foreach (KeyValuePair<Type, dynamic> handler in this.handlers)
|
||||
foreach (KeyValuePair<Type, dynamic> handler in addedHandlers)
|
||||
{
|
||||
if (handler.Key == typeof(TNotification))
|
||||
{
|
||||
@@ -26,14 +26,12 @@ public class Mediator(IServiceProvider provider) :
|
||||
|
||||
if (handlers.Count == 0)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else if (handlers.Count == 1)
|
||||
{
|
||||
return handlers[0].Handle(notification, cancellationToken);
|
||||
await handlers[0].Handle(notification, cancellationToken);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> request,
|
||||
@@ -82,7 +80,7 @@ public class Mediator(IServiceProvider provider) :
|
||||
if (interfaceType.GetGenericArguments() is { Length: 1 } arguments)
|
||||
{
|
||||
Type notificationType = arguments[0];
|
||||
handlers.Add(notificationType, subject);
|
||||
addedHandlers.Add(notificationType, subject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public record CollectionChanged<TCollection>(TCollection Items) : INotification where TCollection : IEnumerable;
|
||||
@@ -3,19 +3,29 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public class ObservableCollectionViewModel<TItem> :
|
||||
ObservableCollection<TItem>
|
||||
ObservableCollection<TItem>,
|
||||
INotificationHandler<CollectionChanged<IEnumerable<TItem>>>
|
||||
{
|
||||
private readonly IServiceFactory serviceFactory;
|
||||
|
||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory)
|
||||
private SynchronizationContext? context;
|
||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator)
|
||||
{
|
||||
context = SynchronizationContext.Current;
|
||||
|
||||
this.serviceFactory = serviceFactory;
|
||||
mediator.Subscribe(this);
|
||||
}
|
||||
|
||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IEnumerable<TItem> items)
|
||||
{
|
||||
context = SynchronizationContext.Current;
|
||||
|
||||
this.serviceFactory = serviceFactory;
|
||||
mediator.Subscribe(this);
|
||||
|
||||
AddRange(items);
|
||||
}
|
||||
|
||||
@@ -31,7 +41,7 @@ public class ObservableCollectionViewModel<TItem> :
|
||||
where T : TItem
|
||||
{
|
||||
T? item = serviceFactory.Create<T>(parameters);
|
||||
Add(item);
|
||||
context?.Post(state => Add(item), null);
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -41,7 +51,7 @@ public class ObservableCollectionViewModel<TItem> :
|
||||
TItem
|
||||
{
|
||||
T? item = serviceFactory.Create<T>();
|
||||
Add(item);
|
||||
context?.Post(state => Add(item), null);
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -50,12 +60,19 @@ public class ObservableCollectionViewModel<TItem> :
|
||||
{
|
||||
foreach (TItem? item in items)
|
||||
{
|
||||
Add(item);
|
||||
context?.Post(state => Add(item), null);
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask Handle(CollectionChanged<IEnumerable<TItem>> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
context?.Post(state => Clear(), null);
|
||||
AddRange(notification.Items);
|
||||
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public class ObservableCollectionViewModel(IServiceFactory serviceFactory) :
|
||||
ObservableCollectionViewModel<object>(serviceFactory)
|
||||
{
|
||||
}
|
||||
public class ObservableCollectionViewModel(IServiceFactory serviceFactory, IMediator mediator) :
|
||||
ObservableCollectionViewModel<object>(serviceFactory, mediator);
|
||||
Reference in New Issue
Block a user