reduce mediator duffs

This commit is contained in:
TheXamlGuy
2024-01-07 18:02:04 +00:00
parent 05150c2c03
commit 2e8af23784
24 changed files with 77 additions and 255 deletions
@@ -1,4 +1,3 @@
using Hyperbar.Extensions;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@@ -1,4 +1,3 @@
using Hyperbar.Extensions;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@@ -10,7 +9,6 @@ public class PrimaryWidgetProvider :
public void Create(HostBuilderContext comtext, IServiceCollection services) => public void Create(HostBuilderContext comtext, IServiceCollection services) =>
services.AddConfiguration(comtext.Configuration.GetSection(nameof(PrimaryWidgetConfiguration)), services.AddConfiguration(comtext.Configuration.GetSection(nameof(PrimaryWidgetConfiguration)),
PrimaryWidgetConfiguration.Defaults) PrimaryWidgetConfiguration.Defaults)
.AddTransient<WidgetComponentMappingFactory>() .AddHandler<WidgetComponentMappingHandler>()
.AddTransient(provider => provider.GetRequiredService<WidgetComponentMappingFactory>().Create())
.AddWidgetTemplate<PrimaryWidgetViewModel>(); .AddWidgetTemplate<PrimaryWidgetViewModel>();
} }
@@ -1,4 +1,4 @@
namespace Hyperbar.Windows.Primary; namespace Hyperbar.Windows.Primary;
public class PrimaryWidgetViewModel : public class PrimaryWidgetViewModel :
ObservableCollectionViewModel<IWidgetComponentViewModel>, ObservableCollectionViewModel<IWidgetComponentViewModel>,
@@ -0,0 +1,20 @@
namespace Hyperbar.Windows.Primary;
public class WidgetComponentMappingHandler(PrimaryWidgetConfiguration configuration,
IServiceFactory service,
IMediator mediator) :
IMappingHandler<PrimaryWidgetConfiguration, IEnumerable<IWidgetComponentViewModel>>
{
public IEnumerable<IWidgetComponentViewModel> Handle()
{
foreach (IPrimaryCommandConfiguration item in configuration)
{
if (item is KeyAcceleratorCommandConfiguration keyAcceleratorCommand)
{
yield return service.Create<WidgetButtonViewModel>(keyAcceleratorCommand.Icon, new Action(async () =>
await mediator.SendAsync(new KeyAcceleratorCommand(VirtualKey.LeftWindows))));
}
}
}
}
@@ -1,30 +0,0 @@
namespace Hyperbar.Windows.Primary;
public class WidgetComponentMappingFactory :
IMappingFactory<PrimaryWidgetConfiguration, IEnumerable<IWidgetComponentViewModel>>
{
private readonly PrimaryWidgetConfiguration configuration;
private readonly IServiceFactory service;
private readonly IMediator mediator;
public WidgetComponentMappingFactory(PrimaryWidgetConfiguration configuration,
IServiceFactory service,
IMediator mediator)
{
this.configuration = configuration;
this.service = service;
this.mediator = mediator;
}
public IEnumerable<IWidgetComponentViewModel> Create()
{
foreach (IPrimaryCommandConfiguration item in configuration)
{
if (item is KeyAcceleratorCommandConfiguration keyAcceleratorCommand)
{
yield return service.Create<WidgetButtonViewModel>(keyAcceleratorCommand.Icon, new Action(() =>
mediator.Send(new KeyAcceleratorCommand(VirtualKey.LeftWindows))));
}
}
}
}
+1 -3
View File
@@ -1,11 +1,9 @@
using Hyperbar.Extensions; using Hyperbar.Widget.Contextual;
using Hyperbar.Widget.Contextual;
using Hyperbar.Windows.Controls; using Hyperbar.Windows.Controls;
using Hyperbar.Windows.Primary; using Hyperbar.Windows.Primary;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
namespace Hyperbar.Windows; namespace Hyperbar.Windows;
@@ -1,5 +1,4 @@
using Hyperbar.Extensions; using Hyperbar.Windows.Interop;
using Hyperbar.Windows.Interop;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@@ -32,7 +31,7 @@ namespace Hyperbar.Windows
isolatedServices.AddSingleton<IVirtualKeyboard, VirtualKeyboard>(); isolatedServices.AddSingleton<IVirtualKeyboard, VirtualKeyboard>();
isolatedServices.AddSingleton<IMediator, Mediator>(); isolatedServices.AddSingleton<IMediator, Mediator>();
isolatedServices.AddHandler<KeyAcceleratorCommandHandler>(); isolatedServices.AddHandler<KeyAcceleratorHandler>();
isolatedServices.AddTransient<IWidgetView, WidgetView>(); isolatedServices.AddTransient<IWidgetView, WidgetView>();
isolatedServices.AddContentTemplate<WidgetButtonViewModel, WidgetButtonView>(); isolatedServices.AddContentTemplate<WidgetButtonViewModel, WidgetButtonView>();
@@ -2,8 +2,8 @@
namespace Hyperbar.Windows; namespace Hyperbar.Windows;
public class KeyAcceleratorCommandHandler(IVirtualKeyboard virtualKeyboard) : public class KeyAcceleratorHandler(IVirtualKeyboard virtualKeyboard) :
ICommandHandler<KeyAcceleratorCommand> IRequestHandler<KeyAcceleratorCommand>
{ {
public ValueTask<Unit> Handle(KeyAcceleratorCommand command, public ValueTask<Unit> Handle(KeyAcceleratorCommand command,
CancellationToken cancellationToken) CancellationToken cancellationToken)
+1 -1
View File
@@ -2,4 +2,4 @@
public record KeyAcceleratorCommand(VirtualKey Key, public record KeyAcceleratorCommand(VirtualKey Key,
VirtualKey[]? Modifiers = null) : VirtualKey[]? Modifiers = null) :
ICommand; IRequest;
@@ -1,12 +1,27 @@
namespace Hyperbar; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using System.Threading;
namespace Hyperbar;
public record ConfigurationChanged<TConfiguration>(TConfiguration Configuration) : INotification
where TConfiguration :
class;
public class ConfigurationInitializer<TConfiguration>(DefaultConfiguration<TConfiguration> defaults, public class ConfigurationInitializer<TConfiguration>(DefaultConfiguration<TConfiguration> defaults,
IConfigurationWriter<TConfiguration> writer) : IInitializer IConfigurationWriter<TConfiguration> writer,
IOptionsMonitor<TConfiguration> options,
IMediator mediator) : IInitializer
where TConfiguration : where TConfiguration :
class, new() class, new()
{ {
public Task InitializeAsync() public Task InitializeAsync()
{ {
options.OnChange(args =>
{
mediator.PublishAsync(new ConfigurationChanged<TConfiguration>(args));
});
writer.Write(defaults.Configuration); writer.Write(defaults.Configuration);
return Task.CompletedTask; return Task.CompletedTask;
} }
@@ -6,14 +6,14 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Text.Json; using System.Text.Json;
namespace Hyperbar.Extensions; namespace Hyperbar;
public static class IServiceCollectionExtensions public static class IServiceCollectionExtensions
{ {
public static IServiceCollection AddHandler<THandler>(this IServiceCollection serviceCollection, public static IServiceCollection AddHandler<THandler>(this IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Transient) ServiceLifetime lifetime = ServiceLifetime.Transient)
where THandler : where THandler :
notnull IHandler
{ {
if (typeof(THandler).GetInterface(typeof(INotificationHandler<>).Name) is { } notificationContract) if (typeof(THandler).GetInterface(typeof(INotificationHandler<>).Name) is { } notificationContract)
{ {
@@ -21,13 +21,13 @@ public static class IServiceCollectionExtensions
{ {
Type notificationType = arguments[0]; Type notificationType = arguments[0];
serviceCollection.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), ServiceLifetime.Singleton)); services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), ServiceLifetime.Singleton));
serviceCollection.Add(new ServiceDescriptor(typeof(INotificationHandler<>).MakeGenericType(notificationType), services.Add(new ServiceDescriptor(typeof(INotificationHandler<>).MakeGenericType(notificationType),
provider => provider.GetRequiredService<THandler>(), lifetime)); provider => provider.GetRequiredService<THandler>(), lifetime));
} }
} }
if (typeof(THandler).GetInterface(typeof(IRequestHandler<,>).Name) is { } requestContract) if (typeof(THandler).GetInterface(typeof(IHandler<,>).Name) is { } requestContract)
{ {
if (requestContract.GetGenericArguments() is { Length: 2 } arguments) if (requestContract.GetGenericArguments() is { Length: 2 } arguments)
{ {
@@ -36,8 +36,8 @@ public static class IServiceCollectionExtensions
Type wrapperType = typeof(RequestClassHandlerWrapper<,>).MakeGenericType(requestType, responseType); Type wrapperType = typeof(RequestClassHandlerWrapper<,>).MakeGenericType(requestType, responseType);
serviceCollection.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime)); services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime));
serviceCollection.Add(new ServiceDescriptor(wrapperType, services.Add(new ServiceDescriptor(wrapperType,
provider => provider.GetService<IServiceFactory>()?.Create(wrapperType, provider => provider.GetService<IServiceFactory>()?.Create(wrapperType,
provider.GetRequiredService<THandler>(), provider.GetRequiredService<THandler>(),
provider.GetServices(typeof(IPipelineBehavior<,>).MakeGenericType(requestType, responseType)))!, provider.GetServices(typeof(IPipelineBehavior<,>).MakeGenericType(requestType, responseType)))!,
@@ -46,44 +46,19 @@ public static class IServiceCollectionExtensions
} }
} }
if (typeof(THandler).GetInterface(typeof(ICommandHandler<,>).Name) is { } commandContract) if (typeof(THandler).GetInterface(typeof(IMappingHandler<,>).Name) is { } mappingContract)
{ {
if (commandContract.GetGenericArguments() is { Length: 2 } arguments) if (mappingContract.GetGenericArguments() is { Length: 2 } arguments)
{ {
Type requestType = arguments[0]; Type requestType = arguments[0];
Type responseType = arguments[1]; Type responseType = arguments[1];
Type wrapperType = typeof(CommandClassHandlerWrapper<,>).MakeGenericType(requestType, responseType); services.AddTransient(typeof(THandler));
services.AddTransient(responseType, provider => ((dynamic)provider.GetRequiredService<THandler>()).Handle());
serviceCollection.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime));
serviceCollection.Add(new ServiceDescriptor(wrapperType,
provider => provider.GetService<IServiceFactory>()?.Create(wrapperType,
provider.GetRequiredService<THandler>(),
provider.GetServices(typeof(IPipelineBehavior<,>).MakeGenericType(requestType, responseType)))!,
lifetime
));
} }
} }
if (typeof(THandler).GetInterface(typeof(IQueryHandler<,>).Name) is { } queryContract) return services;
{
if (queryContract.GetGenericArguments() is { Length: 2 } arguments)
{
Type requestType = arguments[0];
Type responseType = arguments[1];
Type wrapperType = typeof(QueryClassHandlerWrapper<,>).MakeGenericType(requestType, responseType);
serviceCollection.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime));
serviceCollection.Add(new ServiceDescriptor(wrapperType,
provider => provider.GetService<IServiceFactory>()?.Create(wrapperType,
provider.GetRequiredService<THandler>(),
provider.GetServices(typeof(IPipelineBehavior<,>).MakeGenericType(requestType, responseType)))!,
lifetime
));
}
}
return serviceCollection;
} }
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services, public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services,
@@ -1,6 +1,6 @@
namespace Hyperbar; namespace Hyperbar;
public interface IMappingFactory<TFrom, TTo> public interface IMapping<TFrom, TTo>
{ {
TTo Create(); TTo Create();
} }
@@ -1,28 +0,0 @@
namespace Hyperbar;
public class CommandClassHandlerWrapper<TRequest, TResponse>
where TRequest :
class,
ICommand<TResponse>
{
private readonly MessageHandlerDelegate<TRequest, TResponse> handler;
public CommandClassHandlerWrapper(ICommandHandler<TRequest, TResponse> concreteHandler,
IEnumerable<IPipelineBehavior<TRequest, TResponse>> pipelineBehaviours)
{
MessageHandlerDelegate<TRequest, TResponse> handler = concreteHandler.Handle;
foreach (IPipelineBehavior<TRequest, TResponse>? pipeline in pipelineBehaviours.Reverse())
{
MessageHandlerDelegate<TRequest, TResponse> handlerCopy = handler;
IPipelineBehavior<TRequest, TResponse> pipelineCopy = pipeline;
handler = (TRequest message, CancellationToken cancellationToken) =>
pipelineCopy.Handle(message, handlerCopy, cancellationToken);
}
this.handler = handler;
}
public ValueTask<TResponse> Handle(TRequest request, CancellationToken cancellationToken) => handler(request, cancellationToken);
}
-5
View File
@@ -1,5 +0,0 @@
namespace Hyperbar;
public interface ICommand : ICommand<Unit>;
public interface ICommand<out TResponse> : IMessage;
-13
View File
@@ -1,13 +0,0 @@
namespace Hyperbar;
public interface ICommandHandler<in TCommand> : ICommandHandler<TCommand, Unit>
where TCommand :
ICommand<Unit>;
public interface ICommandHandler<in TCommand, TResponse>
where TCommand :
ICommand<TResponse>
{
ValueTask<TResponse> Handle(TCommand command,
CancellationToken cancellationToken);
}
@@ -1,6 +1,9 @@
namespace Hyperbar; namespace Hyperbar;
public interface IRequestHandler<in TRequest, TResponse> public interface IHandler;
public interface IHandler<in TRequest, TResponse> :
IHandler
where TRequest : where TRequest :
IRequest<TResponse> IRequest<TResponse>
{ {
@@ -8,8 +11,8 @@ public interface IRequestHandler<in TRequest, TResponse>
CancellationToken cancellationToken); CancellationToken cancellationToken);
} }
public interface IRequestHandler<in TRequest> : public interface IRequestHandler<in TRequest> :
IRequestHandler<TRequest, Unit> IHandler<TRequest, Unit>
where TRequest : where TRequest :
IRequest<Unit> IRequest<Unit>
{ {
+7
View File
@@ -0,0 +1,7 @@
namespace Hyperbar;
public interface IMappingHandler<TFrom, TTo> :
IHandler
{
TTo Handle();
}
-8
View File
@@ -7,17 +7,9 @@ public interface IMediator
where TNotification : where TNotification :
INotification; INotification;
void Send<TResponse>(ICommand<TResponse> command);
ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> request, ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> request,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
ValueTask<TResponse> SendAsync<TResponse>(ICommand<TResponse> command,
CancellationToken cancellationToken = default);
ValueTask<TResponse> SendAsync<TResponse>(IQuery<TResponse> query,
CancellationToken cancellationToken = default);
ValueTask<object?> SendAsync(object message, CancellationToken ValueTask<object?> SendAsync(object message, CancellationToken
cancellationToken = default); cancellationToken = default);
-3
View File
@@ -1,3 +0,0 @@
namespace Hyperbar;
public interface IQuery<out TResponse> : IMessage;
-9
View File
@@ -1,9 +0,0 @@
namespace Hyperbar;
public interface IQueryHandler<in TQuery, TResponse>
where TQuery :
IQuery<TResponse>
{
ValueTask<TResponse> Handle(TQuery query,
CancellationToken cancellationToken);
}
+3
View File
@@ -0,0 +1,3 @@
namespace Hyperbar;
public class Map<TFrom, TTo>;
-70
View File
@@ -50,45 +50,6 @@ public class Mediator(IServiceProvider provider) :
return default; return default;
} }
public ValueTask<TResponse> SendAsync<TResponse>(ICommand<TResponse> command,
CancellationToken cancellationToken = default)
{
dynamic? handler = provider.GetService(typeof(CommandClassHandlerWrapper<,>)
.MakeGenericType(command.GetType(), typeof(TResponse)));
if (handler is not null)
{
return handler.Handle((dynamic)command, cancellationToken);
}
return default;
}
public void Send<TResponse>(ICommand<TResponse> command)
{
dynamic? handler = provider.GetService(typeof(CommandClassHandlerWrapper<,>)
.MakeGenericType(command.GetType(), typeof(TResponse)));
if (handler is not null)
{
_ = handler.Handle((dynamic)command, default(CancellationToken));
}
}
public ValueTask<TResponse> SendAsync<TResponse>(IQuery<TResponse> query,
CancellationToken cancellationToken = default)
{
dynamic? handler = provider.GetService(typeof(QueryClassHandlerWrapper<,>)
.MakeGenericType(query.GetType(), typeof(TResponse)));
if (handler is not null)
{
return handler.Handle((dynamic)query, cancellationToken);
}
return default;
}
public ValueTask<object?> SendAsync(object message, public ValueTask<object?> SendAsync(object message,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
@@ -108,37 +69,6 @@ public class Mediator(IServiceProvider provider) :
} }
} }
if (message.GetType().GetInterface(typeof(ICommand<>).Name) is { } commandType)
{
if (commandType.GetGenericArguments() is { Length: 1 } arguments)
{
Type responseType = arguments[0];
dynamic? handler = provider.GetService(typeof(CommandClassHandlerWrapper<,>)
.MakeGenericType(message.GetType(), responseType));
if (handler is not null)
{
return handler.Handle((dynamic)message, cancellationToken);
}
}
}
if (message.GetType().GetInterface(typeof(IQuery<>).Name) is { } queryType)
{
if (queryType.GetGenericArguments() is { Length: 1 } arguments)
{
Type responseType = arguments[0];
dynamic? handler = provider.GetService(typeof(QueryClassHandlerWrapper<,>)
.MakeGenericType(message.GetType(), responseType));
if (handler is not null)
{
return handler.Handle((dynamic)message, cancellationToken);
}
}
}
return default; return default;
} }
@@ -1,29 +0,0 @@
namespace Hyperbar;
public class QueryClassHandlerWrapper<TRequest, TResponse>
where TRequest :
class,
IQuery<TResponse>
{
private readonly MessageHandlerDelegate<TRequest, TResponse> handler;
public QueryClassHandlerWrapper(IQueryHandler<TRequest, TResponse> concreteHandler,
IEnumerable<IPipelineBehavior<TRequest, TResponse>> pipelineBehaviours)
{
MessageHandlerDelegate<TRequest, TResponse> handler = concreteHandler.Handle;
foreach (IPipelineBehavior<TRequest, TResponse>? pipeline in pipelineBehaviours.Reverse())
{
MessageHandlerDelegate<TRequest, TResponse> handlerCopy = handler;
IPipelineBehavior<TRequest, TResponse> pipelineCopy = pipeline;
handler = (TRequest message, CancellationToken cancellationToken) =>
pipelineCopy.Handle(message, handlerCopy, cancellationToken);
}
this.handler = handler;
}
public ValueTask<TResponse> Handle(TRequest request, CancellationToken cancellationToken) =>
handler(request, cancellationToken);
}
@@ -7,7 +7,7 @@ public class RequestClassHandlerWrapper<TRequest, TResponse>
{ {
private readonly MessageHandlerDelegate<TRequest, TResponse> handler; private readonly MessageHandlerDelegate<TRequest, TResponse> handler;
public RequestClassHandlerWrapper(IRequestHandler<TRequest, TResponse> concreteHandler, public RequestClassHandlerWrapper(IHandler<TRequest, TResponse> concreteHandler,
IEnumerable<IPipelineBehavior<TRequest, TResponse>> pipelineBehaviours) IEnumerable<IPipelineBehavior<TRequest, TResponse>> pipelineBehaviours)
{ {
MessageHandlerDelegate<TRequest, TResponse> handler = concreteHandler.Handle; MessageHandlerDelegate<TRequest, TResponse> handler = concreteHandler.Handle;