fixed a bunch of isses with keyed handlers

This commit is contained in:
TheXamlGuy
2024-06-22 13:03:14 +01:00
parent 8d76b712be
commit 34d3cc313b
10 changed files with 77 additions and 109 deletions
+11 -11
View File
@@ -147,23 +147,23 @@ public class FrameHandler :
}; };
break; break;
} }
}
if (args.Parameters.TryGetValue("IsBackStackEnabled", out object? isBackStackEnabled)) if (args.Parameters.TryGetValue("IsBackStackEnabled", out object? isBackStackEnabled))
{
if (isBackStackEnabled is bool value)
{ {
if (isBackStackEnabled is bool value) navigationOptions.IsNavigationStackEnabled = value;
{
navigationOptions.IsNavigationStackEnabled = value;
}
} }
}
if (args.Parameters.TryGetValue("ClearBackStack", out object? clearBackStack)) if (args.Parameters.TryGetValue("ClearBackStack", out object? clearBackStack))
{
if (clearBackStack is bool value)
{ {
if (clearBackStack is bool value) if (value)
{ {
if (value) postNavigateActions.Add(() => CleanUp());
{
postNavigateActions.Add(() => CleanUp());
}
} }
} }
} }
+1 -2
View File
@@ -24,8 +24,7 @@ public class ComponentBuilder :
services.AddScoped<IComponentHost, ComponentHost>(); services.AddScoped<IComponentHost, ComponentHost>();
services.AddScoped<IServiceFactory>(provider => services.AddScoped<IServiceFactory>(provider =>
new ServiceFactory((type, parameters) => ActivatorUtilities.CreateInstance(provider, type, new ServiceFactory((type, parameters) => ActivatorUtilities.CreateInstance(provider, type, parameters!)));
parameters?.Where(x => x is not null).ToArray()!)));
services.AddSingleton<IDisposer, Disposer>(); services.AddSingleton<IDisposer, Disposer>();
+1 -2
View File
@@ -18,8 +18,7 @@ public class DefaultHostBuilder :
.ConfigureServices((context, services) => .ConfigureServices((context, services) =>
{ {
services.AddScoped<IServiceFactory>(provider => services.AddScoped<IServiceFactory>(provider =>
new ServiceFactory((type, parameters) => ActivatorUtilities.CreateInstance(provider, type, new ServiceFactory((type, parameters) => ActivatorUtilities.CreateInstance(provider, type, parameters!)));
parameters?.Where(x => x is not null).ToArray()!)));
services.AddSingleton<IComponentHostCollection, services.AddSingleton<IComponentHostCollection,
ComponentHostCollection>(); ComponentHostCollection>();
+2 -4
View File
@@ -3,12 +3,10 @@
public class HandlerProvider(SubscriptionCollection subscriptions) : public class HandlerProvider(SubscriptionCollection subscriptions) :
IHandlerProvider IHandlerProvider
{ {
public IEnumerable<object?> Get(Type type, public IEnumerable<object?> Get(object key)
object? key = null)
{ {
var d = subscriptions; var d = subscriptions;
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{type}"; if (subscriptions.TryGetValue(key, out List<WeakReference>? subscribers))
if (subscriptions.TryGetValue(subscriptionKey, out List<WeakReference>? subscribers))
{ {
foreach (WeakReference weakRef in subscribers.ToArray()) foreach (WeakReference weakRef in subscribers.ToArray())
{ {
+1 -2
View File
@@ -2,6 +2,5 @@
public interface IHandlerProvider public interface IHandlerProvider
{ {
IEnumerable<object?> Get(Type type, IEnumerable<object?> Get(object key);
object? key = null);
} }
@@ -49,38 +49,18 @@ public static class IServiceCollectionExtensions
contract.GetGenericArguments() is { Length: 1 } notificationHandlerArguments) contract.GetGenericArguments() is { Length: 1 } notificationHandlerArguments)
{ {
Type notificationType = notificationHandlerArguments[0]; Type notificationType = notificationHandlerArguments[0];
Type wrapperType = typeof(NotificationHandlerWrapper<>).MakeGenericType(notificationType);
Type wrapperType = typeof(NotificationHandlerWrapper<>) string actualKey = $"{(key is not null ? $"{key}:" : "")}{notificationType}";
.MakeGenericType(notificationType);
if (key is not null) services.Add(new ServiceDescriptor(typeof(INotificationHandler<>)
{ .MakeGenericType(notificationType), actualKey, typeof(THandler), lifetime));
services.Add(new ServiceDescriptor(typeof(INotificationHandler<>)
.MakeGenericType(notificationType), key, typeof(THandler), lifetime));
}
else
{
services.Add(new ServiceDescriptor(typeof(INotificationHandler<>)
.MakeGenericType(notificationType), typeof(THandler), lifetime));
}
services.Add(new ServiceDescriptor(wrapperType, actualKey, (provider, registeredKey) =>
if (key is not null)
{
services.Add(new ServiceDescriptor(wrapperType, key, (provider, key) =>
provider.GetService<IServiceFactory>()?.Create(wrapperType, provider.GetService<IServiceFactory>()?.Create(wrapperType,
provider.GetRequiredKeyedService(typeof(INotificationHandler<>).MakeGenericType(notificationType), key), provider.GetRequiredKeyedService(typeof(INotificationHandler<>).MakeGenericType(notificationType), registeredKey),
provider.GetServices(typeof(IPipelineBehaviour<>) provider.GetServices(typeof(IPipelineBehaviour<>)
.MakeGenericType(notificationType)))!, lifetime)); .MakeGenericType(notificationType)))!, lifetime));
}
else
{
services.Add(new ServiceDescriptor(wrapperType, provider =>
provider.GetService<IServiceFactory>()?.Create(wrapperType,
provider.GetRequiredService(typeof(INotificationHandler<>).MakeGenericType(notificationType)),
provider.GetServices(typeof(IPipelineBehaviour<>)
.MakeGenericType(notificationType)))!, lifetime));
}
} }
if (contract.Name == typeof(IHandler<,>).Name && if (contract.Name == typeof(IHandler<,>).Name &&
@@ -89,36 +69,17 @@ public static class IServiceCollectionExtensions
Type requestType = handlerArguments[0]; Type requestType = handlerArguments[0];
Type responseType = handlerArguments[1]; Type responseType = handlerArguments[1];
Type wrapperType = typeof(HandlerWrapper<,>) Type wrapperType = typeof(HandlerWrapper<,>).MakeGenericType(requestType, responseType);
.MakeGenericType(requestType, responseType); string actualKey = $"{(key is not null ? $"{key}:" : "")}{wrapperType}";
if (key is not null) services.Add(new ServiceDescriptor(typeof(THandler), actualKey,
{ typeof(THandler), lifetime));
services.Add(new ServiceDescriptor(typeof(THandler), key,
typeof(THandler), lifetime));
}
else
{
services.Add(new ServiceDescriptor(typeof(THandler),
typeof(THandler), lifetime));
}
if (key is not null) services.Add(new ServiceDescriptor(wrapperType, actualKey, (provider, actualKey) =>
{ provider.GetService<IServiceFactory>()?.Create(wrapperType,
services.Add(new ServiceDescriptor(wrapperType, key, (provider, key) => provider.GetRequiredKeyedService<THandler>(actualKey),
provider.GetService<IServiceFactory>()?.Create(wrapperType, provider.GetServices(typeof(IPipelineBehaviour<,>)
provider.GetRequiredKeyedService<THandler>(key), .MakeGenericType(requestType, responseType)))!, lifetime));
provider.GetServices(typeof(IPipelineBehaviour<,>)
.MakeGenericType(requestType, responseType)))!, lifetime));
}
else
{
services.Add(new ServiceDescriptor(wrapperType, provider =>
provider.GetService<IServiceFactory>()?.Create(wrapperType,
provider.GetRequiredService<THandler>(),
provider.GetServices(typeof(IPipelineBehaviour<,>)
.MakeGenericType(requestType, responseType)))!, lifetime));
}
} }
} }
+31 -25
View File
@@ -13,12 +13,15 @@ public class Mediator(IHandlerProvider handlerProvider,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TMessage : notnull where TMessage : notnull
{ {
List<object?> handlers = GetHandlers<TMessage, TResponse>(message, key); Type messageType = message.GetType();
Type handlerType = typeof(HandlerWrapper<,>).MakeGenericType(messageType, typeof(TResponse));
key = $"{(key is not null ? $"{key}:" : "")}{handlerType}";
List<object?> handlers = GetHandlers(message, handlerType, key);
foreach (object? handler in handlers) foreach (object? handler in handlers)
{ {
MethodInfo? handleMethod = handler?.GetType().GetMethod("Handle", [message.GetType(), typeof(CancellationToken)]); MethodInfo? handleMethod = handler?.GetType().GetMethod("Handle", [message.GetType(), typeof(CancellationToken)]);
if (handleMethod != null) if (handleMethod is not null)
{ {
return await (Task<TResponse?>)handleMethod.Invoke(handler, new object[] { message, cancellationToken })!; return await (Task<TResponse?>)handleMethod.Invoke(handler, new object[] { message, cancellationToken })!;
} }
@@ -33,14 +36,16 @@ public class Mediator(IHandlerProvider handlerProvider,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
Type messageType = message.GetType(); Type messageType = message.GetType();
Type handlerWrapperType = typeof(HandlerWrapper<,>).MakeGenericType(message.GetType(), responseType); Type handlerType = typeof(HandlerWrapper<,>).MakeGenericType(message.GetType(), responseType);
key = $"{(key is not null ? $"{key}:" : "")}{handlerType}";
List<object?> handlers = GetHandlers(message, handlerWrapperType, key);
List<object?> handlers = GetHandlers(message, handlerType, key);
foreach (object? handler in handlers) foreach (object? handler in handlers)
{ {
MethodInfo? handleMethod = handler?.GetType().GetMethod("Handle", [messageType, typeof(CancellationToken)]); MethodInfo? handleMethod = handler?.GetType().GetMethod("Handle",
if (handleMethod != null) [messageType, typeof(CancellationToken)]);
if (handleMethod is not null)
{ {
dynamic task = handleMethod.Invoke(handler, new object[] { message, cancellationToken })!; dynamic task = handleMethod.Invoke(handler, new object[] { message, cancellationToken })!;
await task; await task;
@@ -86,44 +91,45 @@ public class Mediator(IHandlerProvider handlerProvider,
[EnumeratorCancellation] CancellationToken cancellationToken = default) [EnumeratorCancellation] CancellationToken cancellationToken = default)
{ {
Type messageType = message.GetType(); Type messageType = message.GetType();
Type handlerWrapperType = typeof(HandlerWrapper<,>).MakeGenericType(message.GetType(), responseType); Type handlerType = typeof(HandlerWrapper<,>).MakeGenericType(message.GetType(), responseType);
key = $"{(key is not null ? $"{key}:" : "")}{handlerType}";
List<object?> handlers = GetHandlers(message, handlerWrapperType, key); List<object?> handlers = GetHandlers(message, handlerType, key);
foreach (object? handler in handlers) foreach (object? handler in handlers)
{ {
MethodInfo? handleMethod = handler?.GetType().GetMethod("Handle", [messageType, typeof(CancellationToken)]); MethodInfo? handleMethod = handler?.GetType().GetMethod("Handle",
if (handleMethod != null) [messageType, typeof(CancellationToken)]);
if (handleMethod is not null)
{ {
yield return await (Task<object?>)handleMethod.Invoke(handler, new object[] { message, cancellationToken })!; yield return await (Task<object?>)handleMethod.Invoke(handler, new object[] { message, cancellationToken })!;
} }
} }
} }
public async IAsyncEnumerable<TResponse?> HandleManyAsync<TMessage, TResponse>(TMessage message, public async IAsyncEnumerable<TResponse?> HandleManyAsync<TMessage, TResponse>(TMessage message,
object? key = null, object? key = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default) [EnumeratorCancellation] CancellationToken cancellationToken = default)
where TMessage : notnull where TMessage : notnull
{ {
List<object?> handlers = GetHandlers<TMessage, TResponse>(message, key); Type messageType = message.GetType();
Type handlerType = typeof(HandlerWrapper<,>).MakeGenericType(messageType, typeof(TResponse));
key = $"{(key is not null ? $"{key}:" : "")}{handlerType}";
List<object?> handlers = GetHandlers(message, handlerType, key);
foreach (object? handler in handlers) foreach (object? handler in handlers)
{ {
MethodInfo? handleMethod = handler?.GetType().GetMethod("Handle", [message.GetType(), typeof(CancellationToken)]); MethodInfo? handleMethod = handler?.GetType().GetMethod("Handle", [message.GetType(), typeof(CancellationToken)]);
if (handleMethod != null) if (handleMethod is not null)
{ {
yield return await (Task<TResponse?>)handleMethod.Invoke(handler, new object[] { message, cancellationToken })!; yield return await (Task<TResponse?>)handleMethod.Invoke(handler, new object[] { message, cancellationToken })!;
} }
} }
} }
private List<object?> GetHandlers<TMessage, TResponse>(TMessage message, object? key) private List<object?> GetHandlers(object message,
where TMessage : notnull Type handlerWrapperType,
{ object? key)
Type messageType = message.GetType();
Type handlerWrapperType = typeof(HandlerWrapper<,>).MakeGenericType(messageType, typeof(TResponse));
return GetHandlers(message, handlerWrapperType, key);
}
private List<object?> GetHandlers(object message, Type handlerWrapperType, object? key)
{ {
Type messageType = message.GetType(); Type messageType = message.GetType();
Dictionary<Type, List<object?>> handlers = []; Dictionary<Type, List<object?>> handlers = [];
@@ -145,11 +151,11 @@ public class Mediator(IHandlerProvider handlerProvider,
} }
} }
IEnumerable<object?> keyedServices = key != null ? provider.GetKeyedServices(handlerWrapperType, key) : IEnumerable<object?> keyedServices = key is not null ? provider.GetKeyedServices(handlerWrapperType, key) :
provider.GetServices(handlerWrapperType); provider.GetServices(handlerWrapperType);
AddHandlers(keyedServices); AddHandlers(keyedServices);
IEnumerable<object?> additionalHandlers = handlerProvider.Get(messageType, key); IEnumerable<object?> additionalHandlers = handlerProvider.Get(key);
AddHandlers(additionalHandlers); AddHandlers(additionalHandlers);
return handlers.SelectMany(entry => entry.Value).ToList(); return handlers.SelectMany(entry => entry.Value).ToList();
+6 -6
View File
@@ -8,31 +8,31 @@ public class NavigateHandler(NamedComponent scope,
{ {
public Task Handle(NavigateEventArgs args) public Task Handle(NavigateEventArgs args)
{ {
INavigation? navigationScope = null; INavigation? navigation = null;
if (args.Scope is "self" || args.Scope is "new") if (args.Scope is "self" || args.Scope is "new")
{ {
if (args.Sender is IServiceProviderRequired requireServiceProvider) if (args.Sender is IServiceProviderRequired requireServiceProvider)
{ {
if (args.Scope is "self") if (args.Scope is "self")
{ {
navigationScope = requireServiceProvider.Provider.GetRequiredService<INavigation>(); navigation = requireServiceProvider.Provider.GetRequiredService<INavigation>();
} }
if (args.Scope is "new") if (args.Scope is "new")
{ {
IServiceScope serviceScope = requireServiceProvider.Provider.CreateScope(); IServiceScope serviceScope = requireServiceProvider.Provider.CreateScope();
navigationScope = serviceScope.ServiceProvider.GetRequiredService<INavigation>(); navigation = serviceScope.ServiceProvider.GetRequiredService<INavigation>();
} }
} }
} }
if (navigationScope is null) if (navigation is null)
{ {
ComponentScopeDescriptor? descriptor = componentScopeProvider.Get(args.Scope ?? scope.Name); ComponentScopeDescriptor? descriptor = componentScopeProvider.Get(args.Scope ?? scope.Name);
navigationScope = descriptor?.Services?.GetRequiredService<INavigation>(); navigation = descriptor?.Services?.GetRequiredService<INavigation>();
} }
navigationScope?.Navigate(args.Route, args.Sender, navigation?.Navigate(args.Route, args.Sender,
args.Region, args.Navigated, args.Parameters); args.Region, args.Navigated, args.Parameters);
return Task.CompletedTask; return Task.CompletedTask;
+8 -3
View File
@@ -30,10 +30,15 @@ public class Publisher(IHandlerProvider handlerProvider,
Type handlerType = typeof(NotificationHandlerWrapper<>) Type handlerType = typeof(NotificationHandlerWrapper<>)
.MakeGenericType(notificationType); .MakeGenericType(notificationType);
List<object?> handlers = key is not null ? serviceProvider.GetKeyedServices(handlerType, key).ToList() : key = $"{(key is not null ? $"{key}:" : "")}{notificationType}";
serviceProvider.GetServices(handlerType).ToList();
foreach (object? handler in handlerProvider.Get(notificationType, key)) List<object?> handlers = [];
foreach (object? handler in handlerProvider.Get(key))
{
handlers.Add(handler);
}
foreach (object? handler in serviceProvider.GetKeyedServices(handlerType, key))
{ {
handlers.Add(handler); handlers.Add(handler);
} }
@@ -2,6 +2,7 @@
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Xaml.Interactivity; using Avalonia.Xaml.Interactivity;
using Toolkit.Foundation; using Toolkit.Foundation;
using Toolkit.UI.Controls.Avalonia;
namespace Toolkit.UI.Avalonia; namespace Toolkit.UI.Avalonia;