From ac58d15d6778b50b4fbf0e8513a93d1ccb3d03f3 Mon Sep 17 00:00:00 2001 From: Remco Ros Date: Thu, 3 Oct 2019 19:42:24 +0200 Subject: [PATCH 1/2] Use TryAdd vs Add to allow multiple calls to AddMediatr(..) --- .../Registration/ServiceRegistrar.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs b/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs index 6c9b260..dd97dfa 100644 --- a/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs +++ b/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs @@ -211,10 +211,10 @@ private static void Fill(this IList list, T value) public static void AddRequiredServices(IServiceCollection services, MediatRServiceConfiguration serviceConfiguration) { - services.AddTransient(p => p.GetService); - services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>)); - services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPostProcessorBehavior<,>)); - services.Add(new ServiceDescriptor(typeof(IMediator), serviceConfiguration.MediatorImplementationType, serviceConfiguration.Lifetime)); + services.TryAddTransient(p => p.GetService); + services.TryAddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>)); + services.TryAddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPostProcessorBehavior<,>)); + services.TryAdd(new ServiceDescriptor(typeof(IMediator), serviceConfiguration.MediatorImplementationType, serviceConfiguration.Lifetime)); } } } \ No newline at end of file From 8ba4579bf916745859a7006f8436539266911364 Mon Sep 17 00:00:00 2001 From: Remco Ros Date: Fri, 4 Oct 2019 15:55:07 +0200 Subject: [PATCH 2/2] - Add test case for multiple calls to AddMediatr - Fix use of TryAdd, by handling registration of IPipelineBehavior a bit differently --- .../Registration/ServiceRegistrar.cs | 25 +++++++++++++++++-- .../CustomMediatorTests.cs | 15 +++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs b/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs index dd97dfa..b4f4fdb 100644 --- a/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs +++ b/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs @@ -211,10 +211,31 @@ private static void Fill(this IList list, T value) public static void AddRequiredServices(IServiceCollection services, MediatRServiceConfiguration serviceConfiguration) { + // Use TryAdd, so any existing ServiceFactory/IMediator registration doesn't get overriden services.TryAddTransient(p => p.GetService); - services.TryAddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>)); - services.TryAddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPostProcessorBehavior<,>)); services.TryAdd(new ServiceDescriptor(typeof(IMediator), serviceConfiguration.MediatorImplementationType, serviceConfiguration.Lifetime)); + + // Use TryAddTransientExact (see below), we dó want to register our Pre/Post processor behavior, even if (a more concrete) + // registration for IPipelineBehavior<,> already exists. But only once. + services.TryAddTransientExact(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>)); + services.TryAddTransientExact(typeof(IPipelineBehavior<,>), typeof(RequestPostProcessorBehavior<,>)); + } + + /// + /// Adds a new transient registration to the service collection only when no existing registration of the same service type and implementation type exists. + /// In contrast to TryAddTransient, which only checks the service type. + /// + /// The service collection + /// Service type + /// Implementation type + public static void TryAddTransientExact(this IServiceCollection services, Type serviceType, Type implementationType) + { + if (services.Any(reg => reg.ServiceType == serviceType && reg.ImplementationType == implementationType)) + { + return; + } + + services.AddTransient(serviceType, implementationType); } } } \ No newline at end of file diff --git a/test/MediatR.Extensions.Microsoft.DependencyInjection.Tests/CustomMediatorTests.cs b/test/MediatR.Extensions.Microsoft.DependencyInjection.Tests/CustomMediatorTests.cs index d3bc564..e1196d8 100644 --- a/test/MediatR.Extensions.Microsoft.DependencyInjection.Tests/CustomMediatorTests.cs +++ b/test/MediatR.Extensions.Microsoft.DependencyInjection.Tests/CustomMediatorTests.cs @@ -37,5 +37,20 @@ public void ShouldResolveNotificationHandlers() { _provider.GetServices>().Count().ShouldBe(3); } + + [Fact] + public void Can_Call_AddMediatr_multiple_times() + { + IServiceCollection services = new ServiceCollection(); + services.AddSingleton(new Logger()); + services.AddMediatR(cfg => cfg.Using(), typeof(CustomMediatorTests)); + + // Call AddMediatr again, this should NOT override our custom mediatr (With MS DI, last registration wins) + services.AddMediatR(typeof(CustomMediatorTests)); + + var provider = services.BuildServiceProvider(); + var mediator = provider.GetRequiredService(); + mediator.GetType().ShouldBe(typeof(MyCustomMediator)); + } } } \ No newline at end of file