using Microsoft.Extensions.DependencyInjection; using System.Reflection; namespace Toolkit.Foundation; public class Publisher(IHandlerProvider handlerProvider, IServiceFactory serviceFactory, IServiceProvider serviceProvider, IDispatcher dispatcher) : IPublisher { public void Publish(object? key = null) where TMessage : new() => Publish(serviceFactory.Create() ?? new TMessage(), async args => await args(), key); public void Publish(TMessage message) where TMessage : notnull => Publish(message, async args => await args(), null); public void Publish(TMessage message, object? key = null) where TMessage : notnull => Publish(message, async args => await args(), key); public void Publish(object message, Func, Task> marshal, object? key = null) { Type notificationType = message.GetType(); Type handlerType = typeof(NotificationHandlerWrapper<>) .MakeGenericType(notificationType); key = $"{(key is not null ? $"{key}:" : "")}{notificationType}"; List handlers = []; foreach (object? handler in handlerProvider.Get(key)) { handlers.Add(handler); } foreach (object? handler in serviceProvider.GetKeyedServices(handlerType, key)) { handlers.Add(handler); } foreach (object? handler in handlers) { if (handler is not null) { MethodInfo? handleMethod = handler.GetType().GetMethod("Handle", [notificationType]); if (handleMethod is not null) { marshal(() => (Task)handleMethod.Invoke(handler, new object[] { message })!); } } } } public void Publish(object message) => Publish(message, async args => await args(), null); public void Publish() where TMessage : new() => Publish(new TMessage(), async args => await args(), null); public void PublishUI(object? key = null) where TMessage : new() => Publish(new TMessage(), args => dispatcher.Invoke(async () => await args()), key); public void PublishUI(TMessage message) where TMessage : notnull => Publish(message, args => dispatcher.Invoke(async () => await args()), null); public void PublishUI(TMessage message, object? key = null) where TMessage : notnull => Publish(message, args => dispatcher.Invoke(async () => await args()), key); public void PublishUI() where TMessage : new() => Publish(new TMessage(), args => dispatcher.Invoke(async () => await args()), null); public void PublishUI(object message) => Publish(message, args => dispatcher.Invoke(async () => await args()), null); }