Allow the Mediator to be subscribed to and therefore handled

This commit is contained in:
TheXamlGuy
2024-05-15 19:28:08 +01:00
parent 7e57c0d28d
commit 8c0436644a
6 changed files with 67 additions and 24 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ public class HandlerProvider(SubscriptionCollection subscriptions) :
IHandlerProvider IHandlerProvider
{ {
public IEnumerable<object?> Get(Type type, public IEnumerable<object?> Get(Type type,
object key) object? key = null)
{ {
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{type}"; string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{type}";
if (subscriptions.TryGetValue(subscriptionKey, out List<WeakReference>? subscribers)) if (subscriptions.TryGetValue(subscriptionKey, out List<WeakReference>? subscribers))
+2 -1
View File
@@ -3,6 +3,7 @@ namespace Toolkit.Foundation
{ {
public interface IHandlerProvider public interface IHandlerProvider
{ {
IEnumerable<object?> Get(Type type, object key); IEnumerable<object?> Get(Type type,
object? key = null);
} }
} }
+6 -2
View File
@@ -3,7 +3,11 @@ namespace Toolkit.Foundation
{ {
public interface IMediator public interface IMediator
{ {
Task<object?> Handle(object message, CancellationToken cancellationToken = default); Task<object?> Handle(object message,
Task<TResponse?> Handle<TRequest, TResponse>(TRequest request, CancellationToken cancellationToken = default) where TRequest : notnull; CancellationToken cancellationToken = default);
Task<TResponse?> Handle<TMessage, TResponse>(TMessage message,
CancellationToken cancellationToken = default)
where TMessage : notnull;
} }
} }
+46 -11
View File
@@ -1,27 +1,62 @@
using System.Reflection; using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public class Mediator(IServiceProvider provider) : public class Mediator(IHandlerProvider handlerProvider,
IServiceProvider provider) :
IMediator IMediator
{ {
public Task<TResponse?> Handle<TRequest, TResponse>(TRequest request, public async Task<TResponse?> Handle<TMessage, TResponse>(TMessage message,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TRequest : notnull where TMessage : notnull
{ {
Type handlerType = typeof(HandlerWrapper<,>).MakeGenericType(request.GetType(), Type messageType = message.GetType();
typeof(TResponse)); Type handlerWrapperType = typeof(HandlerWrapper<,>).MakeGenericType(messageType, typeof(TResponse));
if (provider.GetService(handlerType) Dictionary<Type, List<object?>> handlers = [];
is object handler)
foreach (object? service in provider.GetServices(handlerWrapperType))
{ {
if (handlerType.GetMethod("Handle") is MethodInfo handleMethod) if (service?.GetType() is Type serviceType)
{ {
return (Task<TResponse?>)handleMethod.Invoke(handler, new object[] { request, cancellationToken })!; if (!handlers.TryGetValue(serviceType, out List<object?>? handlerList))
{
handlerList = [];
handlers.Add(serviceType, handlerList);
}
handlerList.Add(service);
} }
} }
return Task.FromResult<TResponse?>(default); foreach (object? handler in handlerProvider.Get(messageType))
{
if (handler is not null)
{
Type handlerType = handler.GetType();
if (!handlers.TryGetValue(handlerType, out List<object?>? handlerList))
{
handlerList = [];
handlers.Add(handlerType, handlerList);
}
handlerList.Add(handler);
}
}
foreach (KeyValuePair<Type, List<object?>> handlerEntry in handlers)
{
foreach (object? handler in handlerEntry.Value)
{
if (handler?.GetType().GetMethod("Handle") is MethodInfo handleMethod)
{
return await (Task<TResponse?>)handleMethod.Invoke(handler,
new object[] { message, cancellationToken })!;
}
}
}
return default;
} }
public Task<object?> Handle(object message, public Task<object?> Handle(object message,
+5 -7
View File
@@ -25,12 +25,11 @@ public class Publisher(IHandlerProvider handlerProvider,
object? key = null) object? key = null)
{ {
Type notificationType = message.GetType(); Type notificationType = message.GetType();
Type handlerType = typeof(NotificationHandlerWrapper<>)
.MakeGenericType(notificationType);
List<object?> handlers = provider.GetServices(typeof(NotificationHandlerWrapper<>) List<object?> handlers = provider.GetServices(handlerType).ToList();
.MakeGenericType(notificationType)).ToList(); foreach (object? handler in handlerProvider.Get(notificationType, key))
foreach (object? handler in handlerProvider
.Get(notificationType, key!))
{ {
handlers.Add(handler); handlers.Add(handler);
} }
@@ -39,8 +38,7 @@ public class Publisher(IHandlerProvider handlerProvider,
{ {
if (handler is not null) if (handler is not null)
{ {
Type? handlerType = handler.GetType(); MethodInfo? handleMethod = handler.GetType().GetMethod("Handle",
MethodInfo? handleMethod = handlerType.GetMethod("Handle",
[notificationType]); [notificationType]);
if (handleMethod is not null) if (handleMethod is not null)
+7 -2
View File
@@ -76,6 +76,11 @@ public class Subscription(SubscriptionCollection subscriptions,
? handler.GetPropertyValue(() => attribute.Key) is { } value ? value : attribute.Key : null; ? handler.GetPropertyValue(() => attribute.Key) is { } value ? value : attribute.Key : null;
private IEnumerable<Type> GetHandlerInterfaces(Type handlerType) => private IEnumerable<Type> GetHandlerInterfaces(Type handlerType) =>
handlerType.GetInterfaces().Where(interfaceType => interfaceType.IsGenericType && handlerType.GetInterfaces().Where(interfaceType =>
interfaceType.GetGenericTypeDefinition() == typeof(INotificationHandler<>)); {
Type? definition = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : null;
return definition == typeof(INotificationHandler<>) ||
definition == typeof(IHandler<>) ||
definition == typeof(IHandler<,>);
});
} }