diff --git a/src/Mediator.SourceGenerator/Implementation/Models/NotificationMessageHandlerModel.cs b/src/Mediator.SourceGenerator/Implementation/Models/NotificationMessageHandlerModel.cs index dad46261..f0158083 100644 --- a/src/Mediator.SourceGenerator/Implementation/Models/NotificationMessageHandlerModel.cs +++ b/src/Mediator.SourceGenerator/Implementation/Models/NotificationMessageHandlerModel.cs @@ -1,4 +1,4 @@ -using Mediator.SourceGenerator.Extensions; +using Mediator.SourceGenerator.Extensions; namespace Mediator.SourceGenerator; @@ -19,8 +19,10 @@ public NotificationMessageHandlerModel(NotificationMessageHandler handler, Compi if (!handler.Symbol.IsGenericType) { - var concreteRegistration = - $"services.TryAdd(new {sd}(typeof({concreteSymbol}), typeof({concreteSymbol}), {analyzer.ServiceLifetime}));"; + var concreteRegistration = $""" + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof({concreteSymbol}), typeof({concreteSymbol}))) + services.TryAdd(new {sd}(typeof({concreteSymbol}), typeof({concreteSymbol}), {analyzer.ServiceLifetime})); + """; builder.Add(concreteRegistration); } @@ -29,14 +31,19 @@ public NotificationMessageHandlerModel(NotificationMessageHandler handler, Compi var requestType = message.Symbol.GetTypeSymbolFullName(); if (handler.Symbol.IsGenericType) { - var concreteRegistration = - $"services.TryAdd(new {sd}(typeof({concreteSymbol}<{requestType}>), typeof({concreteSymbol}<{requestType}>), {analyzer.ServiceLifetime}));"; + var concreteRegistration = $""" + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof({concreteSymbol}<{requestType}>), typeof({concreteSymbol}<{requestType}>))) + services.TryAdd(new {sd}(typeof({concreteSymbol}<{requestType}>), typeof({concreteSymbol}<{requestType}>), {analyzer.ServiceLifetime})); + """; builder.Add(concreteRegistration); } - var getExpression = - $"GetRequiredService<{concreteSymbol}{(handler.Symbol.IsGenericType ? $"<{requestType}>" : "")}>()"; - var registration = - $"services.Add(new {sd}(typeof({interfaceSymbol}<{requestType}>), {getExpression}, {analyzer.ServiceLifetime}));"; + + var concreteImpl = $"{concreteSymbol}{(handler.Symbol.IsGenericType ? $"<{requestType}>" : "")}"; + var getExpression = $"GetRequiredService<{concreteImpl}>()"; + var registration = $""" + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof({interfaceSymbol}<{requestType}>), typeof({concreteImpl}))) + services.Add(new {sd}(typeof({interfaceSymbol}<{requestType}>), {getExpression}, {analyzer.ServiceLifetime})); + """; builder.Add(registration); } diff --git a/src/Mediator.SourceGenerator/Implementation/resources/Mediator.sbn-cs b/src/Mediator.SourceGenerator/Implementation/resources/Mediator.sbn-cs index dafb3b38..7c1e9456 100644 --- a/src/Mediator.SourceGenerator/Implementation/resources/Mediator.sbn-cs +++ b/src/Mediator.SourceGenerator/Implementation/resources/Mediator.sbn-cs @@ -49,6 +49,9 @@ namespace Microsoft.Extensions.DependencyInjection throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + {{~ if ServiceLifetimeIsTransient || ServiceLifetimeIsScoped ~}} services.Add(new {{ SD }}(typeof(global::{{ MediatorNamespace }}.Mediator), typeof(global::{{ MediatorNamespace }}.Mediator), {{ ServiceLifetime }})); services.TryAdd(new {{ SD }}(typeof(global::Mediator.IMediator), typeof(global::{{ MediatorNamespace }}.Mediator), {{ ServiceLifetime }})); @@ -61,7 +64,7 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAdd(new {{ SD }}(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), {{ ServiceLifetime }})); {{~ end ~}} {{~ if (object.size RequestMessages) > 0 ~}} - + // Register handlers for request messages {{~ for message in RequestMessages ~}} {{ message.Handler.ServiceRegistration }} @@ -70,14 +73,14 @@ namespace Microsoft.Extensions.DependencyInjection {{~ end ~}} {{~ end ~}} {{~ if (object.size NotificationMessages) > 0 ~}} - + // Register handlers and wrappers for notification messages {{~ for message in NotificationMessages ~}} services.Add(new {{ SD }}(typeof({{ message.HandlerWrapperTypeNameWithGenericTypeArguments }}), typeof({{ message.HandlerWrapperTypeNameWithGenericTypeArguments }}), {{ SingletonServiceLifetime }})); {{~ end ~}} {{~ end ~}} {{~ if (object.size NotificationMessageHandlers) > 0 ~}} - + // Register notification handlers {{~ for handler in NotificationMessageHandlers ~}} {{~ for registration in handler.ServiceRegistrations ~}} @@ -86,7 +89,7 @@ namespace Microsoft.Extensions.DependencyInjection {{~ end ~}} {{~ end ~}} {{~ if (object.size PipelineBehaviors) > 0 ~}} - + // Register pipeline behaviors configured through options {{~ for behavior in PipelineBehaviors ~}} {{~ for registration in behavior.ServiceRegistrations ~}} @@ -94,7 +97,7 @@ namespace Microsoft.Extensions.DependencyInjection {{~ end ~}} {{~ end ~}} {{~ end ~}} - + // Register the notification publisher that was configured {{~ if ServiceLifetimeIsScoped || ServiceLifetimeIsTransient ~}} services.Add(new {{ SD }}(typeof({{ NotificationPublisherType.FullName }}), typeof({{ NotificationPublisherType.FullName }}), {{ ServiceLifetime }})); @@ -103,18 +106,68 @@ namespace Microsoft.Extensions.DependencyInjection services.Add(new {{ SD }}(typeof({{ NotificationPublisherType.FullName }}), typeof({{ NotificationPublisherType.FullName }}), {{ SingletonServiceLifetime }})); services.TryAdd(new {{ SD }}(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService<{{ NotificationPublisherType.FullName }}>(), {{ SingletonServiceLifetime }})); {{~ end ~}} - + // Register internal components services.Add(new {{ SD }}(typeof(global::{{ InternalsNamespace }}.IContainerProbe), typeof(global::{{ InternalsNamespace }}.ContainerProbe0), {{ ServiceLifetime }})); services.Add(new {{ SD }}(typeof(global::{{ InternalsNamespace }}.IContainerProbe), typeof(global::{{ InternalsNamespace }}.ContainerProbe1), {{ ServiceLifetime }})); services.Add(new {{ SD }}(typeof(global::{{ InternalsNamespace }}.ContainerMetadata), typeof(global::{{ InternalsNamespace }}.ContainerMetadata), {{ SingletonServiceLifetime }})); - + return services; - - {{~ if HasNotifications ~}} + + {{~ if HasNotifications ~}} [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); - {{~ end ~}} + {{~ end ~}} + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/BasicTests.Multiple_Notification_Handlers_One_Class#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/BasicTests.Multiple_Notification_Handlers_One_Class#Mediator.g.verified.cs index 5293617c..5201fbbb 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/BasicTests.Multiple_Notification_Handlers_One_Class#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/BasicTests.Multiple_Notification_Handlers_One_Class#Mediator.g.verified.cs @@ -50,34 +50,90 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.RequestHandler), typeof(global::TestCode.RequestHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RequestHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RequestHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/BasicTests.Multiple_Request_Handlers_One_Class#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/BasicTests.Multiple_Request_Handlers_One_Class#Mediator.g.verified.cs index dccb1df4..81637bff 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/BasicTests.Multiple_Request_Handlers_One_Class#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/BasicTests.Multiple_Request_Handlers_One_Class#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -62,18 +65,68 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_TypeOf#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_TypeOf#Mediator.g.verified.cs index 8f280830..06b52a98 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_TypeOf#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_TypeOf#Mediator.g.verified.cs @@ -50,27 +50,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_TypeOf_Assembly#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_TypeOf_Assembly#Mediator.g.verified.cs index 8f280830..06b52a98 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_TypeOf_Assembly#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_TypeOf_Assembly#Mediator.g.verified.cs @@ -50,27 +50,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_Valid_Reference#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_Valid_Reference#Mediator.g.verified.cs index 6da330c1..a7a48375 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_Valid_Reference#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_Assemblies_Valid_Reference#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Request0Handler), typeof(global::TestCode.Request0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.Request0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -62,18 +65,68 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Library1.Request1Handler), typeof(global::TestCode.Library1.Request1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.Library1.Request1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_ForEachAwaitPublisher_Default#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_ForEachAwaitPublisher_Default#Mediator.g.verified.cs index 6da9d57a..a225a756 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_ForEachAwaitPublisher_Default#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_ForEachAwaitPublisher_Default#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_GenerateTypesAsInternal_value=False#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_GenerateTypesAsInternal_value=False#Mediator.g.verified.cs index 6da9d57a..a225a756 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_GenerateTypesAsInternal_value=False#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_GenerateTypesAsInternal_value=False#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_GenerateTypesAsInternal_value=True#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_GenerateTypesAsInternal_value=True#Mediator.g.verified.cs index 8d50b635..246d0f50 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_GenerateTypesAsInternal_value=True#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_GenerateTypesAsInternal_value=True#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_PipelineBehaviors#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_PipelineBehaviors#Mediator.g.verified.cs index 0725fe4b..03ee5328 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_PipelineBehaviors#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_PipelineBehaviors#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -62,7 +65,7 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamRequestHandler), typeof(global::TestCode.RequestHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamRequestHandlerWrapper), typeof(global::Mediator.Internals.StreamRequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register pipeline behaviors configured through options services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPipelineBehavior), typeof(global::TestCode.GenericBehavior), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPipelineBehavior), typeof(global::TestCode.GenericRequestBehavior), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -72,18 +75,68 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamPipelineBehavior), typeof(global::TestCode.StreamGenericBehavior), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamPipelineBehavior), typeof(global::TestCode.StreamGenericRequestBehavior), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamPipelineBehavior), typeof(global::TestCode.StreamConcreteBehavior), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_TaskWhenAllPublisher_For_Notifications_AddMediator#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_TaskWhenAllPublisher_For_Notifications_AddMediator#Mediator.g.verified.cs index d4bb94b3..bd05c5a4 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_TaskWhenAllPublisher_For_Notifications_AddMediator#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_TaskWhenAllPublisher_For_Notifications_AddMediator#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.TaskWhenAllPublisher), typeof(global::Mediator.TaskWhenAllPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_TaskWhenAllPublisher_For_Notifications_Attribute#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_TaskWhenAllPublisher_For_Notifications_Attribute#Mediator.g.verified.cs index ee6cae91..ae2a841a 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_TaskWhenAllPublisher_For_Notifications_Attribute#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ConfigurationTests.Test_TaskWhenAllPublisher_For_Notifications_Attribute#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.TaskWhenAllPublisher), typeof(global::Mediator.TaskWhenAllPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/LifetimeOptionTests.Test_No_Args#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/LifetimeOptionTests.Test_No_Args#Mediator.g.verified.cs index 6da9d57a..a225a756 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/LifetimeOptionTests.Test_No_Args#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/LifetimeOptionTests.Test_No_Args#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/LifetimeOptionTests.Test_Transient_Lifetime_With_Named_Namespace_Arg#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/LifetimeOptionTests.Test_Transient_Lifetime_With_Named_Namespace_Arg#Mediator.g.verified.cs index a86be48f..a28f37d0 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/LifetimeOptionTests.Test_Transient_Lifetime_With_Named_Namespace_Arg#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/LifetimeOptionTests.Test_Transient_Lifetime_With_Named_Namespace_Arg#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator2.Mediator), typeof(global::Mediator2.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator2.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator2.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator2.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator2.Internals.IContainerProbe), typeof(global::Mediator2.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator2.Internals.IContainerProbe), typeof(global::Mediator2.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator2.Internals.ContainerMetadata), typeof(global::Mediator2.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/MessageOrderingTests.Test_Notifications_Ordering#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/MessageOrderingTests.Test_Notifications_Ordering#Mediator.g.verified.cs index 73a94091..181d3ab7 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/MessageOrderingTests.Test_Notifications_Ordering#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/MessageOrderingTests.Test_Notifications_Ordering#Mediator.g.verified.cs @@ -50,49 +50,117 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.DomainEventHandler), typeof(global::TestCode.DomainEventHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundCreatedHandler), typeof(global::TestCode.RoundCreatedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundResultedHandler), typeof(global::TestCode.RoundResultedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundSucceededHandler), typeof(global::TestCode.RoundSucceededHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundSucceededActuallyHandler), typeof(global::TestCode.RoundSucceededActuallyHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.DomainEventHandler), typeof(global::TestCode.DomainEventHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.DomainEventHandler), typeof(global::TestCode.DomainEventHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.RoundCreatedHandler), typeof(global::TestCode.RoundCreatedHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundCreatedHandler), typeof(global::TestCode.RoundCreatedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundCreatedHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.RoundResultedHandler), typeof(global::TestCode.RoundResultedHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundResultedHandler), typeof(global::TestCode.RoundResultedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundResultedHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.RoundSucceededHandler), typeof(global::TestCode.RoundSucceededHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundSucceededHandler), typeof(global::TestCode.RoundSucceededHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundSucceededHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundSucceededHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.RoundSucceededActuallyHandler), typeof(global::TestCode.RoundSucceededActuallyHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundSucceededActuallyHandler), typeof(global::TestCode.RoundSucceededActuallyHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundSucceededActuallyHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/MessageOrderingTests.Test_Notifications_Ordering_Bigger#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/MessageOrderingTests.Test_Notifications_Ordering_Bigger#Mediator.g.verified.cs index 847a2723..d952c8ea 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/MessageOrderingTests.Test_Notifications_Ordering_Bigger#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/MessageOrderingTests.Test_Notifications_Ordering_Bigger#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -66,53 +69,133 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.DomainEventHandler), typeof(global::TestCode.DomainEventHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundCreatedHandler), typeof(global::TestCode.RoundCreatedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundResultedHandler), typeof(global::TestCode.RoundResultedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundSucceededHandler), typeof(global::TestCode.RoundSucceededHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundSucceededActuallyHandler), typeof(global::TestCode.RoundSucceededActuallyHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.DomainEvent2Handler), typeof(global::TestCode.DomainEvent2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Round2CreatedHandler), typeof(global::TestCode.Round2CreatedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Round2ResultedHandler), typeof(global::TestCode.Round2ResultedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Round2SucceededHandler), typeof(global::TestCode.Round2SucceededHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Round2SucceededActuallyHandler), typeof(global::TestCode.Round2SucceededActuallyHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.DomainEventHandler), typeof(global::TestCode.DomainEventHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.DomainEventHandler), typeof(global::TestCode.DomainEventHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEventHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.RoundCreatedHandler), typeof(global::TestCode.RoundCreatedHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundCreatedHandler), typeof(global::TestCode.RoundCreatedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundCreatedHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.RoundResultedHandler), typeof(global::TestCode.RoundResultedHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundResultedHandler), typeof(global::TestCode.RoundResultedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundResultedHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.RoundSucceededHandler), typeof(global::TestCode.RoundSucceededHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundSucceededHandler), typeof(global::TestCode.RoundSucceededHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundSucceededHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundSucceededHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundSucceededHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.RoundSucceededActuallyHandler), typeof(global::TestCode.RoundSucceededActuallyHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.RoundSucceededActuallyHandler), typeof(global::TestCode.RoundSucceededActuallyHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.RoundSucceededActuallyHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.DomainEvent2Handler), typeof(global::TestCode.DomainEvent2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.DomainEvent2Handler), typeof(global::TestCode.DomainEvent2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEvent2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEvent2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEvent2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.DomainEvent2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.Round2CreatedHandler), typeof(global::TestCode.Round2CreatedHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Round2CreatedHandler), typeof(global::TestCode.Round2CreatedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.Round2CreatedHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.Round2ResultedHandler), typeof(global::TestCode.Round2ResultedHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Round2ResultedHandler), typeof(global::TestCode.Round2ResultedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.Round2ResultedHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.Round2SucceededHandler), typeof(global::TestCode.Round2SucceededHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Round2SucceededHandler), typeof(global::TestCode.Round2SucceededHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.Round2SucceededHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.Round2SucceededActuallyHandler), typeof(global::TestCode.Round2SucceededActuallyHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Round2SucceededActuallyHandler), typeof(global::TestCode.Round2SucceededActuallyHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.Round2SucceededActuallyHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/NotificationsTests.Test_Notifications_DI#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/NotificationsTests.Test_Notifications_DI#Mediator.g.verified.cs index cc769c68..f35f4c92 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/NotificationsTests.Test_Notifications_DI#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/NotificationsTests.Test_Notifications_DI#Mediator.g.verified.cs @@ -50,58 +50,136 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.CatchAllNotificationHandler), typeof(global::TestCode.CatchAllNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.SpecialGenericNotificationHandler), typeof(global::TestCode.SpecialGenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.SpecialGenericNotificationHandler), typeof(global::TestCode.SpecialGenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.SpecialCatchAllNotificationHandler), typeof(global::TestCode.SpecialCatchAllNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Notification0Handler), typeof(global::TestCode.Notification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Notification1Handler), typeof(global::TestCode.Notification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Notification2Handler), typeof(global::TestCode.Notification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Notification3Handler), typeof(global::TestCode.Notification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.GenericNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.GenericNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.GenericNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.GenericNotificationHandler), typeof(global::TestCode.GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.GenericNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.CatchAllNotificationHandler), typeof(global::TestCode.CatchAllNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.CatchAllNotificationHandler), typeof(global::TestCode.CatchAllNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.CatchAllNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.CatchAllNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.SpecialGenericNotificationHandler), typeof(global::TestCode.SpecialGenericNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.SpecialGenericNotificationHandler), typeof(global::TestCode.SpecialGenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.SpecialGenericNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.SpecialGenericNotificationHandler), typeof(global::TestCode.SpecialGenericNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.SpecialGenericNotificationHandler), typeof(global::TestCode.SpecialGenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.SpecialGenericNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.SpecialCatchAllNotificationHandler), typeof(global::TestCode.SpecialCatchAllNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.SpecialCatchAllNotificationHandler), typeof(global::TestCode.SpecialCatchAllNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.SpecialCatchAllNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.Notification0Handler), typeof(global::TestCode.Notification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Notification0Handler), typeof(global::TestCode.Notification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.Notification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.Notification1Handler), typeof(global::TestCode.Notification1Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Notification1Handler), typeof(global::TestCode.Notification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.Notification1Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.Notification2Handler), typeof(global::TestCode.Notification2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Notification2Handler), typeof(global::TestCode.Notification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.Notification2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.Notification3Handler), typeof(global::TestCode.Notification3Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.Notification3Handler), typeof(global::TestCode.Notification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.Notification3Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Scoped#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Scoped#Mediator.g.verified.cs index 1ca3137b..d414bd1e 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Scoped#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Scoped#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); @@ -122,28 +125,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Singleton#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Singleton#Mediator.g.verified.cs index 7f355081..ac9e4149 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Singleton#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Singleton#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -122,28 +125,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Transient#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Transient#Mediator.g.verified.cs index 62f63d90..2473479f 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Transient#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Command_serviceLifetime=Transient#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); @@ -122,28 +125,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Scoped#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Scoped#Mediator.g.verified.cs index 33b9e86b..50e80370 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Scoped#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Scoped#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); @@ -74,7 +77,7 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -93,57 +96,141 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification1Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification3Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification4Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification5Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification6Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification7Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification8Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification9Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification10Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification11Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification12Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification13Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification14Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification15Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification16Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Singleton#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Singleton#Mediator.g.verified.cs index 47cd9307..771a4705 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Singleton#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Singleton#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -74,7 +77,7 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -93,57 +96,141 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification1Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification3Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification4Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification5Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification6Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification7Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification8Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification9Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification10Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification11Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification12Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification13Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification14Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification15Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification16Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Transient#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Transient#Mediator.g.verified.cs index 53951874..4b23d8e4 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Transient#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Notification_serviceLifetime=Transient#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); @@ -74,7 +77,7 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -93,57 +96,141 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification1Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification3Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification4Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification5Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification6Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification7Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification8Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification9Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification10Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification11Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification12Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification13Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification14Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification15Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification16Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Scoped#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Scoped#Mediator.g.verified.cs index e7aa2e6f..57a2bb4a 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Scoped#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Scoped#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); @@ -122,28 +125,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Singleton#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Singleton#Mediator.g.verified.cs index 01f45cb1..efc35922 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Singleton#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Singleton#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -122,28 +125,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Transient#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Transient#Mediator.g.verified.cs index 357c1ae1..db0206f3 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Transient#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Query_serviceLifetime=Transient#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); @@ -122,28 +125,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Scoped#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Scoped#Mediator.g.verified.cs index a98c1788..22d98deb 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Scoped#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Scoped#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); @@ -122,28 +125,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Singleton#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Singleton#Mediator.g.verified.cs index 52a5313a..51ff22c4 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Singleton#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Singleton#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -122,28 +125,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Transient#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Transient#Mediator.g.verified.cs index 65bc0444..77002c60 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Transient#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=Request_serviceLifetime=Transient#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); @@ -122,28 +125,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Scoped#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Scoped#Mediator.g.verified.cs index ad2a9fd0..48bf384c 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Scoped#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Scoped#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); @@ -74,28 +77,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Singleton#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Singleton#Mediator.g.verified.cs index 9e418bee..cd4f6bfe 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Singleton#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Singleton#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -74,28 +77,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Transient#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Transient#Mediator.g.verified.cs index 398ed774..8e0c4739 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Transient#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamCommand_serviceLifetime=Transient#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); @@ -74,28 +77,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Scoped#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Scoped#Mediator.g.verified.cs index ad2a9fd0..48bf384c 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Scoped#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Scoped#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); @@ -74,28 +77,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Singleton#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Singleton#Mediator.g.verified.cs index 9e418bee..cd4f6bfe 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Singleton#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Singleton#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -74,28 +77,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Transient#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Transient#Mediator.g.verified.cs index 398ed774..8e0c4739 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Transient#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamQuery_serviceLifetime=Transient#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); @@ -74,28 +77,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Scoped#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Scoped#Mediator.g.verified.cs index ad2a9fd0..48bf384c 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Scoped#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Scoped#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); @@ -74,28 +77,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Singleton#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Singleton#Mediator.g.verified.cs index 9e418bee..cd4f6bfe 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Singleton#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Singleton#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -74,28 +77,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Transient#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Transient#Mediator.g.verified.cs index 398ed774..8e0c4739 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Transient#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Size_Uneven_manyOfMessageType=StreamRequest_serviceLifetime=Transient#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); @@ -74,28 +77,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand0Handler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Scoped#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Scoped#Mediator.g.verified.cs index 4c941743..034fb851 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Scoped#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Scoped#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); @@ -344,7 +347,7 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand15Handler), typeof(global::TestCode.TestStreamCommand15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -362,55 +365,137 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification1Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification3Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification4Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification5Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification6Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification7Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification8Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification9Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification10Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification11Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification12Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification13Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification14Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification15Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Singleton#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Singleton#Mediator.g.verified.cs index 952ac5d4..664fe560 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Singleton#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Singleton#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -344,7 +347,7 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand15Handler), typeof(global::TestCode.TestStreamCommand15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -362,55 +365,137 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification1Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification3Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification4Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification5Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification6Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification7Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification8Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification9Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification10Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification11Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification12Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification13Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification14Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification15Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Transient#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Transient#Mediator.g.verified.cs index 2ad9bed9..f8704951 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Transient#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=16_serviceLifetime=Transient#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); @@ -344,7 +347,7 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand15Handler), typeof(global::TestCode.TestStreamCommand15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -362,55 +365,137 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification1Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification3Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification4Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification5Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification6Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification7Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification8Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification9Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification10Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification11Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification12Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification13Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification14Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification15Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Scoped#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Scoped#Mediator.g.verified.cs index 651599d4..38c2377e 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Scoped#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Scoped#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); @@ -362,7 +365,7 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand16Handler), typeof(global::TestCode.TestStreamCommand16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -381,57 +384,141 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification1Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification3Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification4Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification5Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification6Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification7Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification8Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification9Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification10Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification11Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification12Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification13Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification14Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification15Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification16Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Singleton#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Singleton#Mediator.g.verified.cs index 1beddce4..e67ff156 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Singleton#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Singleton#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -362,7 +365,7 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand16Handler), typeof(global::TestCode.TestStreamCommand16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -381,57 +384,141 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification1Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification3Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification4Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification5Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification6Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification7Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification8Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification9Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification10Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification11Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification12Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification13Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification14Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification15Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification16Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Transient#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Transient#Mediator.g.verified.cs index faaaf14c..3c6a178c 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Transient#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ProjectTypeTests.Test_Project_Sizes_n=17_serviceLifetime=Transient#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestRequest0Handler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::TestCode.TestRequest0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); @@ -362,7 +365,7 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestStreamCommand16Handler), typeof(global::TestCode.TestStreamCommand16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamCommandHandler), typeof(global::TestCode.TestStreamCommand16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), typeof(global::Mediator.Internals.StreamCommandHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -381,57 +384,141 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification0Handler), typeof(global::TestCode.TestNotification0Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification0Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification1Handler), typeof(global::TestCode.TestNotification1Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification1Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification2Handler), typeof(global::TestCode.TestNotification2Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification2Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification3Handler), typeof(global::TestCode.TestNotification3Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification3Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification4Handler), typeof(global::TestCode.TestNotification4Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification4Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification5Handler), typeof(global::TestCode.TestNotification5Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification5Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification6Handler), typeof(global::TestCode.TestNotification6Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification6Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification7Handler), typeof(global::TestCode.TestNotification7Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification7Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification8Handler), typeof(global::TestCode.TestNotification8Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification8Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification9Handler), typeof(global::TestCode.TestNotification9Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification9Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification10Handler), typeof(global::TestCode.TestNotification10Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification10Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification11Handler), typeof(global::TestCode.TestNotification11Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification11Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification12Handler), typeof(global::TestCode.TestNotification12Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification12Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification13Handler), typeof(global::TestCode.TestNotification13Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification13Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification14Handler), typeof(global::TestCode.TestNotification14Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification14Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification15Handler), typeof(global::TestCode.TestNotification15Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification15Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::TestCode.TestNotification16Handler), typeof(global::TestCode.TestNotification16Handler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::TestCode.TestNotification16Handler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Abstract_Handler_Program#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Abstract_Handler_Program#Mediator.g.verified.cs index cc5c1a55..507a2960 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Abstract_Handler_Program#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Abstract_Handler_Program#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Byte_Array_Response_Program#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Byte_Array_Response_Program#Mediator.g.verified.cs index f5229859..2cf6cf3e 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Byte_Array_Response_Program#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Byte_Array_Response_Program#Mediator.g.verified.cs @@ -50,27 +50,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Some.Nested.Types.Program.PingHandler), typeof(global::Some.Nested.Types.Program.PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::Some.Nested.Types.Program.PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Const_Variable_In_Config#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Const_Variable_In_Config#Mediator.g.verified.cs index 68035a9e..11588e50 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Const_Variable_In_Config#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Const_Variable_In_Config#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsole.Mediator.Mediator), typeof(global::SimpleConsole.Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::SimpleConsole.Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::SimpleConsole.Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::SimpleConsole.Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsole.Mediator.Internals.IContainerProbe), typeof(global::SimpleConsole.Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsole.Mediator.Internals.IContainerProbe), typeof(global::SimpleConsole.Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsole.Mediator.Internals.ContainerMetadata), typeof(global::SimpleConsole.Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Deep_Namespace_Program#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Deep_Namespace_Program#Mediator.g.verified.cs index 75c9d585..1632571e 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Deep_Namespace_Program#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Deep_Namespace_Program#Mediator.g.verified.cs @@ -50,27 +50,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Some.Very.Very.Very.Very.Deep.Namespace.ThatIUseToTestTheSourceGenSoThatItCanHandleLotsOfDifferentInput.PingHandler), typeof(global::Some.Very.Very.Very.Very.Deep.Namespace.ThatIUseToTestTheSourceGenSoThatItCanHandleLotsOfDifferentInput.PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::Some.Very.Very.Very.Very.Deep.Namespace.ThatIUseToTestTheSourceGenSoThatItCanHandleLotsOfDifferentInput.PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Duplicate_Handlers#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Duplicate_Handlers#Mediator.g.verified.cs index 775dc48d..cab2fc7b 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Duplicate_Handlers#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Duplicate_Handlers#Mediator.g.verified.cs @@ -50,27 +50,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::PingHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Empty_Program#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Empty_Program#Mediator.g.verified.cs index 6da9d57a..a225a756 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Empty_Program#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Empty_Program#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Invalid_Handler_Type#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Invalid_Handler_Type#Mediator.g.verified.cs index cc5c1a55..507a2960 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Invalid_Handler_Type#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Invalid_Handler_Type#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Local_Literal_Variable_In_Config#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Local_Literal_Variable_In_Config#Mediator.g.verified.cs index dc25d7a9..93d3a475 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Local_Literal_Variable_In_Config#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Local_Literal_Variable_In_Config#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SomeNamespace.Mediator), typeof(global::SomeNamespace.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::SomeNamespace.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::SomeNamespace.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::SomeNamespace.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SomeNamespace.Internals.IContainerProbe), typeof(global::SomeNamespace.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SomeNamespace.Internals.IContainerProbe), typeof(global::SomeNamespace.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SomeNamespace.Internals.ContainerMetadata), typeof(global::SomeNamespace.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Local_Variables_Referencing_Consts_Config#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Local_Variables_Referencing_Consts_Config#Mediator.g.verified.cs index dc25d7a9..93d3a475 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Local_Variables_Referencing_Consts_Config#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Local_Variables_Referencing_Consts_Config#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SomeNamespace.Mediator), typeof(global::SomeNamespace.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::SomeNamespace.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::SomeNamespace.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::SomeNamespace.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SomeNamespace.Internals.IContainerProbe), typeof(global::SomeNamespace.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SomeNamespace.Internals.IContainerProbe), typeof(global::SomeNamespace.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SomeNamespace.Internals.ContainerMetadata), typeof(global::SomeNamespace.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Multiple_AddMediator_Calls#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Multiple_AddMediator_Calls#Mediator.g.verified.cs index 8eb592b3..fe57bd2a 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Multiple_AddMediator_Calls#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Multiple_AddMediator_Calls#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Scoped)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Multiple_Errors#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Multiple_Errors#Mediator.g.verified.cs index 775dc48d..cab2fc7b 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Multiple_Errors#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Multiple_Errors#Mediator.g.verified.cs @@ -50,27 +50,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::PingHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_No_Messages_Program#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_No_Messages_Program#Mediator.g.verified.cs index 6da9d57a..a225a756 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_No_Messages_Program#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_No_Messages_Program#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Notification_Without_Any_Handlers#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Notification_Without_Any_Handlers#Mediator.g.verified.cs index 6079b437..bb8796b4 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Notification_Without_Any_Handlers#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Notification_Without_Any_Handlers#Mediator.g.verified.cs @@ -50,28 +50,81 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Null_Namespace_Variable#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Null_Namespace_Variable#Mediator.g.verified.cs index 6da9d57a..a225a756 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Null_Namespace_Variable#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Null_Namespace_Variable#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Request_Without_Handler_In_Referenced_Library#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Request_Without_Handler_In_Referenced_Library#Mediator.g.verified.cs index cc5c1a55..507a2960 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Request_Without_Handler_In_Referenced_Library#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Request_Without_Handler_In_Referenced_Library#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Request_Without_Handler_Warning#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Request_Without_Handler_Warning#Mediator.g.verified.cs index cc5c1a55..507a2960 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Request_Without_Handler_Warning#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Request_Without_Handler_Warning#Mediator.g.verified.cs @@ -50,22 +50,75 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Static_Nested_Handler_Program#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Static_Nested_Handler_Program#Mediator.g.verified.cs index 0fa96395..483c6d15 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Static_Nested_Handler_Program#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/ReportingTests.Test_Static_Nested_Handler_Program#Mediator.g.verified.cs @@ -50,27 +50,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Some.Nested.Types.Program.PingHandler), typeof(global::Some.Nested.Types.Program.PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::Some.Nested.Types.Program.PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ASPNET_Core_CleanArchitecture_Sample#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ASPNET_Core_CleanArchitecture_Sample#Mediator.g.verified.cs index 8cd08572..980cdc10 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ASPNET_Core_CleanArchitecture_Sample#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ASPNET_Core_CleanArchitecture_Sample#Mediator.g.verified.cs @@ -50,11 +50,14 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::AspNetCoreSample.Application.TodoItemCommandHandler), typeof(global::AspNetCoreSample.Application.TodoItemCommandHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ICommandHandler), typeof(global::AspNetCoreSample.Application.TodoItemCommandHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); @@ -62,18 +65,68 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::AspNetCoreSample.Application.TodoItemQueryHandler), typeof(global::AspNetCoreSample.Application.TodoItemQueryHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IQueryHandler>), typeof(global::AspNetCoreSample.Application.TodoItemQueryHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.QueryHandlerWrapper>), typeof(global::Mediator.Internals.QueryHandlerWrapper>), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ASPNET_Core_Indirect_Sample#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ASPNET_Core_Indirect_Sample#Mediator.g.verified.cs index 9876c215..362d3725 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ASPNET_Core_Indirect_Sample#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ASPNET_Core_Indirect_Sample#Mediator.g.verified.cs @@ -50,27 +50,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::AspNetCoreIndirect.Application.Controllers.GetWeatherForecastHandler), typeof(global::AspNetCoreIndirect.Application.Controllers.GetWeatherForecastHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler>), typeof(global::AspNetCoreIndirect.Application.Controllers.GetWeatherForecastHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper>), typeof(global::Mediator.Internals.RequestHandlerWrapper>), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Console#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Console#Mediator.g.verified.cs index 2daccef9..8d599520 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Console#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Console#Mediator.g.verified.cs @@ -50,27 +50,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsole.Mediator), typeof(global::SimpleConsole.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::PingHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsole.Internals.RequestHandlerWrapper), typeof(global::SimpleConsole.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsole.Internals.IContainerProbe), typeof(global::SimpleConsole.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsole.Internals.IContainerProbe), typeof(global::SimpleConsole.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsole.Internals.ContainerMetadata), typeof(global::SimpleConsole.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ConsoleAOT#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ConsoleAOT#Mediator.g.verified.cs index e726873f..e3777fe0 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ConsoleAOT#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_ConsoleAOT#Mediator.g.verified.cs @@ -50,31 +50,84 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsoleAOT.Mediator), typeof(global::SimpleConsoleAOT.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::PingHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsoleAOT.Internals.RequestHandlerWrapper), typeof(global::SimpleConsoleAOT.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register pipeline behaviors configured through options services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPipelineBehavior), typeof(global::GenericLoggerHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPipelineBehavior), typeof(global::PingValidator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsoleAOT.Internals.IContainerProbe), typeof(global::SimpleConsoleAOT.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsoleAOT.Internals.IContainerProbe), typeof(global::SimpleConsoleAOT.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::SimpleConsoleAOT.Internals.ContainerMetadata), typeof(global::SimpleConsoleAOT.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_InternalMessages_Sample#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_InternalMessages_Sample#Mediator.g.verified.cs index c0c82754..e39e022e 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_InternalMessages_Sample#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_InternalMessages_Sample#Mediator.g.verified.cs @@ -50,37 +50,92 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::InternalMessages.Application.PingHandler), typeof(global::InternalMessages.Application.PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::InternalMessages.Application.PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::InternalMessages.Application.PingPongedHandler), typeof(global::InternalMessages.Application.PingPongedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::InternalMessages.Application.PingPongedHandler), typeof(global::InternalMessages.Application.PingPongedHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::InternalMessages.Application.PingPongedHandler), typeof(global::InternalMessages.Application.PingPongedHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::InternalMessages.Application.PingPongedHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Notifications#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Notifications#Mediator.g.verified.cs index 07f4485e..fbc040bb 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Notifications#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Notifications#Mediator.g.verified.cs @@ -50,36 +50,95 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::GenericNotificationHandler), typeof(global::GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::CatchAllNotificationHandler), typeof(global::CatchAllNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::ConcreteNotificationHandler), typeof(global::ConcreteNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::GenericNotificationHandler), typeof(global::GenericNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::GenericNotificationHandler), typeof(global::GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::GenericNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::CatchAllNotificationHandler), typeof(global::CatchAllNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::CatchAllNotificationHandler), typeof(global::CatchAllNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::CatchAllNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::ConcreteNotificationHandler), typeof(global::ConcreteNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::ConcreteNotificationHandler), typeof(global::ConcreteNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::ConcreteNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Showcase#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Showcase#Mediator.g.verified.cs index 1e4ff2c7..1a2a119c 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Showcase#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Showcase#Mediator.g.verified.cs @@ -50,49 +50,111 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::PingHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IRequestHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.RequestHandlerWrapper), typeof(global::Mediator.Internals.RequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers and wrappers for notification messages services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.NotificationHandlerWrapper), typeof(global::Mediator.Internals.NotificationHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register notification handlers - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::ErrorNotificationHandler), typeof(global::ErrorNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::StatsNotificationHandler), typeof(global::StatsNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::GenericNotificationHandler), typeof(global::GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::GenericNotificationHandler), typeof(global::GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::ErrorNotificationHandler), typeof(global::ErrorNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::ErrorNotificationHandler), typeof(global::ErrorNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::ErrorNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::StatsNotificationHandler), typeof(global::StatsNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::StatsNotificationHandler), typeof(global::StatsNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::StatsNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::StatsNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::GenericNotificationHandler), typeof(global::GenericNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::GenericNotificationHandler), typeof(global::GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::GenericNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::GenericNotificationHandler), typeof(global::GenericNotificationHandler))) + services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::GenericNotificationHandler), typeof(global::GenericNotificationHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + if (!IsHandlerAlreadyRegistered(existingRegistrations, typeof(global::Mediator.INotificationHandler), typeof(global::GenericNotificationHandler))) + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationHandler), GetRequiredService>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); + // Register pipeline behaviors configured through options services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPipelineBehavior), typeof(global::ErrorLoggerHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPipelineBehavior), typeof(global::PingValidator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::FireAndForgetNotificationPublisher), typeof(global::FireAndForgetNotificationPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; - + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static global::System.Func GetRequiredService() where T : notnull => sp => sp.GetRequiredService(); } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); + } } } diff --git a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Streaming#Mediator.g.verified.cs b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Streaming#Mediator.g.verified.cs index a0feb1f5..7b8f9ac7 100644 --- a/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Streaming#Mediator.g.verified.cs +++ b/test/Mediator.SourceGenerator.Tests/_snapshots/SampleTests.Test_Streaming#Mediator.g.verified.cs @@ -50,27 +50,80 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g throw new global::System.Exception(errMsg); } + // Build cache of existing registrations for efficient lookup + var existingRegistrations = BuildRegistrationCache(services); + services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Mediator), typeof(global::Mediator.Mediator), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IMediator), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ISender), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register handlers for request messages services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::PingHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.IStreamRequestHandler), typeof(global::PingHandler), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.StreamRequestHandlerWrapper), typeof(global::Mediator.Internals.StreamRequestHandlerWrapper), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register the notification publisher that was configured services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.TryAdd(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + // Register internal components services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.IContainerProbe), typeof(global::Mediator.Internals.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); services.Add(new global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor(typeof(global::Mediator.Internals.ContainerMetadata), typeof(global::Mediator.Internals.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)); - + return services; + + } + + /// + /// Builds a cache of existing service registrations for efficient duplicate detection. + /// Maps service types to their registered implementation types. + /// + /// The service collection to analyze + /// Dictionary mapping service types to sets of implementation types + private static global::System.Collections.Generic.Dictionary> + BuildRegistrationCache(IServiceCollection services) + { + var cache = new global::System.Collections.Generic.Dictionary>(); + + foreach (var service in services) + { + if (service.ServiceType == null) continue; + + if (!cache.ContainsKey(service.ServiceType)) + { + cache[service.ServiceType] = new global::System.Collections.Generic.HashSet(); + } + + // Handle different ServiceDescriptor registration patterns + if (service.ImplementationType != null) + { + cache[service.ServiceType].Add(service.ImplementationType); + } + else if (service.ImplementationInstance != null) + { + cache[service.ServiceType].Add(service.ImplementationInstance.GetType()); + } + } + + return cache; + } + /// + /// Checks if a handler registration already exists in the service collection. + /// + /// Cache of existing registrations + /// The service interface type + /// The concrete implementation type + /// True if the handler is already registered + private static bool IsHandlerAlreadyRegistered( + global::System.Collections.Generic.Dictionary> existingRegistrations, + global::System.Type serviceType, + global::System.Type implementationType) + { + return existingRegistrations.ContainsKey(serviceType) && + existingRegistrations[serviceType].Contains(implementationType); } } } diff --git a/test/Mediator.Tests/CustomRegistrationTests.cs b/test/Mediator.Tests/CustomRegistrationTests.cs new file mode 100644 index 00000000..aad9ee0c --- /dev/null +++ b/test/Mediator.Tests/CustomRegistrationTests.cs @@ -0,0 +1,109 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; + +namespace Mediator.Tests +{ + public class CustomRegistrationTests + { + [Fact] + public void WithoutCustomization_ShouldBeSingleton() + { + var (sp, _) = Fixture.GetMediator(); + + var handlers = sp.GetServices>(); + Assert.NotNull(handlers); + var handlersArray = handlers.Where(h => h is CustomNotificationHandler).ToArray(); + Assert.NotNull(handlersArray); + Assert.Single(handlersArray); + + var handlers2 = sp.GetServices>(); + Assert.NotNull(handlers2); + var handlers2Array = handlers2.Where(h => h is CustomNotificationHandler).ToArray(); + Assert.NotNull(handlers2Array); + Assert.Single(handlers2Array); + + Assert.Same(handlersArray[0], handlers2Array[0]); // must be same instance + } + + [Fact] + public void WhenHandlerIsAlreadyRegistered_AsSingleton_DoesNotRegisterDuplicate() + { + var services = new ServiceCollection(); + services.AddSingleton, CustomNotificationHandler>(); + + var (sp, _) = Fixture.GetMediator(services); + + var handlers = sp.GetServices>(); + Assert.NotNull(handlers); + var handlersArray = handlers.Where(h => h is CustomNotificationHandler).ToArray(); + Assert.NotNull(handlersArray); + Assert.Single(handlersArray); + + var handlers2 = sp.GetServices>(); + Assert.NotNull(handlers2); + var handlers2Array = handlers2.Where(h => h is CustomNotificationHandler).ToArray(); + Assert.NotNull(handlers2Array); + Assert.Single(handlers2Array); + + Assert.Same(handlersArray[0], handlers2Array[0]); // must be same instance + } + + [Fact] + public void WhenHandlerIsAlreadyRegistered_AsType_DoesNotRegisterDuplicate() + { + var services = new ServiceCollection(); + services.AddTransient, CustomNotificationHandler>(); + + var (sp, _) = Fixture.GetMediator(services); + + var handlers = sp.GetServices>(); + Assert.NotNull(handlers); + var handlersArray = handlers.Where(h => h is CustomNotificationHandler).ToArray(); + Assert.NotNull(handlersArray); + Assert.Single(handlersArray); + + var handlers2 = sp.GetServices>(); + Assert.NotNull(handlers2); + var handlers2Array = handlers2.Where(h => h is CustomNotificationHandler).ToArray(); + Assert.NotNull(handlers2Array); + Assert.Single(handlers2Array); + + Assert.NotSame(handlersArray[0], handlers2Array[0]); // must be same instance + } + + [Fact] + public void WhenHandlerIsAlreadyRegistered_AsInstance_DoesNotRegisterDuplicate() + { + var services = new ServiceCollection(); + services.AddSingleton>(new CustomNotificationHandler()); + + var (sp, _) = Fixture.GetMediator(services); + + var handlers = sp.GetServices>(); + Assert.NotNull(handlers); + var handlersArray = handlers.Where(h => h is CustomNotificationHandler).ToArray(); + Assert.NotNull(handlersArray); + Assert.Single(handlersArray); + + var handlers2 = sp.GetServices>(); + Assert.NotNull(handlers2); + var handlers2Array = handlers2.Where(h => h is CustomNotificationHandler).ToArray(); + Assert.NotNull(handlers2Array); + Assert.Single(handlers2Array); + + Assert.Same(handlersArray[0], handlers2Array[0]); // must be same instance + } + } + + public record CustomNotification : INotification { } + + public class CustomNotificationHandler : INotificationHandler + { + public ValueTask Handle(CustomNotification notification, CancellationToken cancellationToken) + { + return new(); + } + } +} diff --git a/test/Mediator.Tests/Fixture.cs b/test/Mediator.Tests/Fixture.cs index d306e777..0a8eb08d 100644 --- a/test/Mediator.Tests/Fixture.cs +++ b/test/Mediator.Tests/Fixture.cs @@ -15,10 +15,14 @@ public static class Fixture public static (IServiceProvider sp, IMediator mediator) GetMediator( Action? configureServices = null, bool? createScope = null + ) => GetMediator(new ServiceCollection(), configureServices, createScope); + + public static (IServiceProvider sp, IMediator mediator) GetMediator( + ServiceCollection services, + Action? configureServices = null, + bool? createScope = null ) { - var services = new ServiceCollection(); - services.AddMediator(); configureServices?.Invoke(services);