WIP to allow mediter handlers to be subscribed to

This commit is contained in:
TheXamlGuy
2024-05-14 22:49:16 +01:00
parent 32829d1cf3
commit 7e57c0d28d
15 changed files with 81 additions and 83 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ public partial class CommandValueViewModel<TValue>(IServiceProvider provider,
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer) :
ValueViewModel<TValue>(provider, factory, mediator, publisher, subscriber, disposer)
{
+1 -1
View File
@@ -6,7 +6,7 @@ public partial class CommandViewModel(IServiceProvider provider,
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer) :
ObservableViewModel(provider, factory, mediator, publisher, subscriber, disposer)
{
+6 -3
View File
@@ -27,11 +27,14 @@ public class ComponentBuilder :
new ServiceFactory((type, parameters) =>
ActivatorUtilities.CreateInstance(provider, type, parameters!)));
services.AddScoped<SubscriptionCollection>();
services.AddScoped<ISubscriptionManager, SubscriptionManager>();
services.AddSingleton<IDisposer, Disposer>();
services.AddTransient<ISubscriber, Subscriber>();
services.AddScoped<SubscriptionCollection>();
services.AddTransient<IHandlerProvider, HandlerProvider>();
services.AddTransient<ISubscription, Subscription>();
services.AddTransient<ISubscription, Subscription>();
services.AddTransient<IPublisher, Publisher>();
services.AddTransient<IMediator, Mediator>();
@@ -12,7 +12,7 @@ public partial class ComponentConfigurationViewModel<TConfiguration, TValue, THe
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer,
THeader header,
TDescription description,
@@ -30,7 +30,7 @@ public partial class ComponentConfigurationViewModel<TConfiguration, TValue, TAc
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer,
TAction action,
TConfiguration configuration,
@@ -72,7 +72,7 @@ public partial class ComponentConfigurationViewModel<TConfiguration, TValue, TDe
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer,
TAction action,
TDescription description,
+4 -2
View File
@@ -26,9 +26,11 @@ public class DefaultHostBuilder :
services.AddSingleton<IDisposer, Disposer>();
services.AddScoped<SubscriptionCollection>();
services.AddTransient<ISubscriptionManager, SubscriptionManager>();
services.AddTransient<ISubscriber, Subscriber>();
services.AddTransient<IHandlerProvider, HandlerProvider>();
services.AddTransient<ISubscription, Subscription>();
services.AddTransient<ISubscription, Subscription>();
services.AddTransient<IPublisher, Publisher>();
services.AddTransient<IMediator, Mediator>();
+26
View File
@@ -0,0 +1,26 @@
namespace Toolkit.Foundation;
public class HandlerProvider(SubscriptionCollection subscriptions) :
IHandlerProvider
{
public IEnumerable<object?> Get(Type type,
object key)
{
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{type}";
if (subscriptions.TryGetValue(subscriptionKey, out List<WeakReference>? subscribers))
{
foreach (WeakReference weakRef in subscribers.ToArray())
{
object? target = weakRef.Target;
if (target != null)
{
yield return target;
}
else
{
subscribers.Remove(weakRef);
}
}
}
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace Toolkit.Foundation
{
public interface IHandlerProvider
{
IEnumerable<object?> Get(Type type, object key);
}
}
@@ -1,8 +1,8 @@
namespace Toolkit.Foundation;
public interface ISubscriber
public interface ISubscription
{
void Remove(object subscriber);
void Add(object subscriber);
void Remove(object subscriber);
}
@@ -1,10 +0,0 @@
namespace Toolkit.Foundation;
public interface ISubscriptionManager
{
IEnumerable<object?> GetHandlers(Type notificationType, object key);
void Remove(object subscriber);
void Add(object subscriber);
}
@@ -41,7 +41,7 @@ public partial class ObservableCollectionViewModel<TViewModel> :
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer)
{
Provider = provider;
@@ -59,7 +59,7 @@ public partial class ObservableCollectionViewModel<TViewModel> :
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer,
IEnumerable<TViewModel> items)
{
@@ -459,7 +459,7 @@ public partial class ObservableCollectionViewModel<TValue, TViewModel>(IServiceP
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber, IDisposer disposer) : ObservableCollectionViewModel<TViewModel>(provider, factory, mediator, publisher, subscriber, disposer)
ISubscription subscriber, IDisposer disposer) : ObservableCollectionViewModel<TViewModel>(provider, factory, mediator, publisher, subscriber, disposer)
where TViewModel : notnull
{
[ObservableProperty]
@@ -470,6 +470,6 @@ public class ObservableCollectionViewModel(IServiceProvider provider,
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer) :
ObservableCollectionViewModel<IDisposable>(provider, factory, mediator, publisher, subscriber, disposer);
+3 -3
View File
@@ -19,7 +19,7 @@ public partial class ObservableViewModel :
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer)
{
Provider = provider;
@@ -80,7 +80,7 @@ public partial class ObservableViewModel<TValue>(IServiceProvider provider,
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer) : ObservableViewModel(provider, factory, mediator, publisher, subscriber, disposer)
where TValue : notnull
{
@@ -92,7 +92,7 @@ public partial class ObservableViewModel<TKey, TValue>(IServiceProvider provider
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer,
TValue? value = null) : ObservableViewModel(provider, factory, mediator, publisher, subscriber, disposer)
where TValue : class
+3 -3
View File
@@ -3,7 +3,7 @@ using System.Reflection;
namespace Toolkit.Foundation;
public class Publisher(ISubscriptionManager subscriptionManager,
public class Publisher(IHandlerProvider handlerProvider,
IServiceProvider provider,
IDispatcher dispatcher) :
IPublisher
@@ -29,8 +29,8 @@ public class Publisher(ISubscriptionManager subscriptionManager,
List<object?> handlers = provider.GetServices(typeof(NotificationHandlerWrapper<>)
.MakeGenericType(notificationType)).ToList();
foreach (object? handler in subscriptionManager
.GetHandlers(notificationType, key!))
foreach (object? handler in handlerProvider
.Get(notificationType, key!))
{
handlers.Add(handler);
}
-11
View File
@@ -1,11 +0,0 @@
namespace Toolkit.Foundation;
public class Subscriber(ISubscriptionManager subscriptionManager) :
ISubscriber
{
public void Remove(object subscriber) =>
subscriptionManager.Remove(subscriber);
public void Add(object subscriber) =>
subscriptionManager.Add(subscriber);
}
@@ -2,27 +2,26 @@
namespace Toolkit.Foundation;
public class SubscriptionManager(SubscriptionCollection subscriptions,
IDisposer disposer) :
ISubscriptionManager
public class Subscription(SubscriptionCollection subscriptions,
IDisposer disposer) :
ISubscription
{
public IEnumerable<object?> GetHandlers(Type notificationType,
object key)
public void Add(object subscriber)
{
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{notificationType}";
if (subscriptions.TryGetValue(subscriptionKey, out List<WeakReference>? subscribers))
Type handlerType = subscriber.GetType();
object? key = GetKeyFromHandler(subscriber);
foreach (Type interfaceType in GetHandlerInterfaces(handlerType))
{
foreach (WeakReference weakRef in subscribers.ToArray())
if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
{
object? target = weakRef.Target;
if (target != null)
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{argumentType}";
subscriptions.AddOrUpdate(subscriptionKey, _ => new List<WeakReference> { new(subscriber) }, (_, collection) =>
{
yield return target;
}
else
{
subscribers.Remove(weakRef);
}
collection.Add(new WeakReference(subscriber));
return collection;
});
disposer.Add(subscriber, Disposable.Create(() => RemoveSubscriber(subscriber, argumentType)));
}
}
}
@@ -50,27 +49,8 @@ public class SubscriptionManager(SubscriptionCollection subscriptions,
}
}
public void Add(object subscriber)
{
Type handlerType = subscriber.GetType();
object? key = GetKeyFromHandler(subscriber);
foreach (Type interfaceType in GetHandlerInterfaces(handlerType))
{
if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
{
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{argumentType}";
subscriptions.AddOrUpdate(subscriptionKey, _ => new List<WeakReference> { new(subscriber) }, (_, collection) =>
{
collection.Add(new WeakReference(subscriber));
return collection;
});
disposer.Add(subscriber, Disposable.Create(() => RemoveSubscriber(subscriber, argumentType)));
}
}
}
private void RemoveSubscriber(object subscriber,
private void RemoveSubscriber(object subscriber,
Type argumentType)
{
string subscriptionKey = $"{argumentType}";
@@ -91,11 +71,11 @@ public class SubscriptionManager(SubscriptionCollection subscriptions,
}
}
private object? GetKeyFromHandler(object handler) =>
private object? GetKeyFromHandler(object handler) =>
handler.GetAttribute<NotificationAttribute>() is NotificationAttribute attribute
? handler.GetPropertyValue(() => attribute.Key) is { } value ? value : attribute.Key : null;
private IEnumerable<Type> GetHandlerInterfaces(Type handlerType) =>
handlerType.GetInterfaces().Where(interfaceType => interfaceType.IsGenericType &&
interfaceType.GetGenericTypeDefinition() == typeof(INotificationHandler<>));
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ public partial class ValueViewModel<TValue>(IServiceProvider provider,
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber,
ISubscription subscriber,
IDisposer disposer) :
ObservableViewModel(provider, factory, mediator, publisher, subscriber, disposer)
{