From ebe190d12d51ba8f8bdeee730889ef14fb35537a Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 27 Jan 2019 13:43:49 +0000 Subject: [PATCH 1/4] Change default log level to debug Change the default logging level for the integration tests to Debug. --- JustSaying.IntegrationTests/Fluent/IntegrationTestBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JustSaying.IntegrationTests/Fluent/IntegrationTestBase.cs b/JustSaying.IntegrationTests/Fluent/IntegrationTestBase.cs index 41ffaec63..0f51697ea 100644 --- a/JustSaying.IntegrationTests/Fluent/IntegrationTestBase.cs +++ b/JustSaying.IntegrationTests/Fluent/IntegrationTestBase.cs @@ -50,7 +50,7 @@ protected IServiceCollection Given(Action configure) protected IServiceCollection Given(Action configure) { return new ServiceCollection() - .AddLogging((p) => p.AddXUnit(OutputHelper)) + .AddLogging((p) => p.AddXUnit(OutputHelper).SetMinimumLevel(LogLevel.Debug)) .AddJustSaying( (builder, serviceProvider) => { From 354fcbd76087bc9d1f641ca77d21d91f731d0475 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 27 Jan 2019 13:45:26 +0000 Subject: [PATCH 2/4] Enforce single handler for Microsoft DI Enforce a single handler registration per message type for the Microsoft DI IHandlerResolver implementation to match the previous behaviour with StructureMap. Add debug-level logging for handler resolution. --- .../ServiceProviderResolver.cs | 54 ++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/JustSaying.Extensions.DependencyInjection.Microsoft/ServiceProviderResolver.cs b/JustSaying.Extensions.DependencyInjection.Microsoft/ServiceProviderResolver.cs index af06c8ad6..a253dfc24 100644 --- a/JustSaying.Extensions.DependencyInjection.Microsoft/ServiceProviderResolver.cs +++ b/JustSaying.Extensions.DependencyInjection.Microsoft/ServiceProviderResolver.cs @@ -1,7 +1,9 @@ using System; +using System.Linq; using JustSaying.Fluent; using JustSaying.Messaging.MessageHandling; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace JustSaying { @@ -17,9 +19,15 @@ internal sealed class ServiceProviderResolver : IServiceResolver, IHandlerResolv /// The to use. internal ServiceProviderResolver(IServiceProvider serviceProvider) { - ServiceProvider = serviceProvider; + ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + Logger = serviceProvider.GetRequiredService>(); } + /// + /// Gets the to use. + /// + private ILogger Logger { get; } + /// /// Gets the to use. /// @@ -27,7 +35,49 @@ internal ServiceProviderResolver(IServiceProvider serviceProvider) /// public IHandlerAsync ResolveHandler(HandlerResolutionContext context) - => ServiceProvider.GetRequiredService>(); + { + bool logAtDebug = Logger.IsEnabled(LogLevel.Debug); + + if (logAtDebug) + { + Logger.LogDebug( + "Resolving handler for message type {MessageType} for queue {QueueName}.", + typeof(T).FullName, + context.QueueName); + } + + var handlers = ServiceProvider.GetServices>().ToArray(); + + if (handlers.Length == 0) + { + throw new NotSupportedException($"No handler for message type {typeof(T).FullName} is registered."); + } + else if (handlers.Length > 1) + { + if (logAtDebug) + { + Logger.LogDebug( + "Resolved handler types for message type {MessageType} for queue {QueueName}: {ResolvedHandlerTypes}", + typeof(T).FullName, + context.QueueName, + string.Join(", ", handlers.Select((p) => p.GetType().FullName))); + } + + throw new NotSupportedException($"{handlers.Length} handlers for message type {typeof(T).FullName} are registered. Only one handler is supported per message type."); + } + + var handler = handlers[0]; + + if (logAtDebug) + { + Logger.LogDebug( + "Resolved handler of type {ResolvedHandlerType} for queue {QueueName}.", + handler.GetType().FullName, + context.QueueName); + } + + return handler; + } /// public T ResolveService() From b4940da4690eae60b3cc5ac55a2db796b5cea4f8 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 27 Jan 2019 13:48:06 +0000 Subject: [PATCH 3/4] Migrate container integration tests Migrate the integration tests for container registration of handler to the new fluent interface. Remove redundant tests for named handlers which just provided a test implementation that tested itself. --- ...dlerViaContainerWithMissingRegistration.cs | 32 ++++++++++ ...enRegisteringASingleHandlerViaContainer.cs | 47 ++++++++++++++ ...RegisteringMultipleHandlersViaContainer.cs | 36 +++++++++++ .../BlockingHandlerRegistry.cs | 14 ----- .../GivenAPublisher.cs | 61 ------------------- .../MultipleHandlerRegistry.cs | 18 ------ .../NamedHandlerResolverTests.cs | 41 ------------- .../SingleHandlerRegistry.cs | 15 ----- .../StructureMapHandlerResolver.cs | 18 ------ .../StructuremapNamedHandlerResolver.cs | 38 ------------ .../TestHandlers.cs | 25 -------- ...dlerViaContainerWithMissingRegistration.cs | 42 ------------- ...enRegisteringASingleHandlerViaContainer.cs | 47 -------------- ...RegisteringMultipleHandlersViaContainer.cs | 44 ------------- 14 files changed, 115 insertions(+), 363 deletions(-) create mode 100644 JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringAHandlerViaContainerWithMissingRegistration.cs create mode 100644 JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringASingleHandlerViaContainer.cs create mode 100644 JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringMultipleHandlersViaContainer.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/BlockingHandlerRegistry.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/GivenAPublisher.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/MultipleHandlerRegistry.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/NamedHandlerResolverTests.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/SingleHandlerRegistry.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/StructureMapHandlerResolver.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/StructuremapNamedHandlerResolver.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/TestHandlers.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringAHandlerViaContainerWithMissingRegistration.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringASingleHandlerViaContainer.cs delete mode 100644 JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringMultipleHandlersViaContainer.cs diff --git a/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringAHandlerViaContainerWithMissingRegistration.cs b/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringAHandlerViaContainerWithMissingRegistration.cs new file mode 100644 index 000000000..38b925267 --- /dev/null +++ b/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringAHandlerViaContainerWithMissingRegistration.cs @@ -0,0 +1,32 @@ +using System; +using JustSaying.IntegrationTests.TestHandlers; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Xunit; +using Xunit.Abstractions; + +namespace JustSaying.IntegrationTests.Fluent.DependencyInjection.Microsoft +{ + public class WhenRegisteringAHandlerViaContainerWithMissingRegistration : IntegrationTestBase + { + public WhenRegisteringAHandlerViaContainerWithMissingRegistration(ITestOutputHelper outputHelper) + : base(outputHelper) + { + } + + [AwsFact] + public void Then_An_Exception_Is_Thrown() + { + // Arrange + var future = new Future(); + + var serviceProvider = GivenJustSaying() + .ConfigureJustSaying((builder) => builder.WithLoopbackQueue(UniqueName)) + .BuildServiceProvider(); + + // Act and Assert + var exception = Assert.Throws(() => serviceProvider.GetService()); + exception.Message.ShouldBe("No handler for message type JustSaying.IntegrationTests.TestHandlers.OrderPlaced is registered."); + } + } +} diff --git a/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringASingleHandlerViaContainer.cs b/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringASingleHandlerViaContainer.cs new file mode 100644 index 000000000..cd1754652 --- /dev/null +++ b/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringASingleHandlerViaContainer.cs @@ -0,0 +1,47 @@ +using System; +using System.Threading.Tasks; +using JustSaying.IntegrationTests.TestHandlers; +using JustSaying.Messaging; +using JustSaying.Messaging.MessageHandling; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Xunit.Abstractions; + +namespace JustSaying.IntegrationTests.Fluent.DependencyInjection.Microsoft +{ + public class WhenRegisteringASingleHandlerViaContainer : IntegrationTestBase + { + public WhenRegisteringASingleHandlerViaContainer(ITestOutputHelper outputHelper) + : base(outputHelper) + { + } + + [AwsFact] + public async Task Then_The_Handler_Is_Resolved() + { + // Arrange + var future = new Future(); + + var services = GivenJustSaying() + .ConfigureJustSaying((builder) => builder.WithLoopbackQueue(UniqueName)) + .AddTransient, OrderProcessor>() + .AddSingleton(future); + + await WhenAsync( + services, + async (publisher, listener, cancellationToken) => + { + listener.Start(cancellationToken); + + var message = new OrderPlaced(Guid.NewGuid().ToString()); + + // Act + await publisher.PublishAsync(message, cancellationToken); + + //Assert + await future.DoneSignal; + future.ReceivedMessageCount.ShouldBeGreaterThan(0); + }); + } + } +} diff --git a/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringMultipleHandlersViaContainer.cs b/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringMultipleHandlersViaContainer.cs new file mode 100644 index 000000000..82d45ef6f --- /dev/null +++ b/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenRegisteringMultipleHandlersViaContainer.cs @@ -0,0 +1,36 @@ +using System; +using JustSaying.IntegrationTests.TestHandlers; +using JustSaying.Messaging.MessageHandling; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Xunit; +using Xunit.Abstractions; + +namespace JustSaying.IntegrationTests.Fluent.DependencyInjection.Microsoft +{ + public class WhenRegisteringMultipleHandlersViaContainer : IntegrationTestBase + { + public WhenRegisteringMultipleHandlersViaContainer(ITestOutputHelper outputHelper) + : base(outputHelper) + { + } + + [AwsFact] + public void Then_An_Exception_Is_Thrown() + { + // Arrange + var future = new Future(); + + var serviceProvider = GivenJustSaying() + .ConfigureJustSaying((builder) => builder.WithLoopbackQueue(UniqueName)) + .AddTransient, OrderProcessor>() + .AddTransient, OrderDispatcher>() + .AddTransient>() + .BuildServiceProvider(); + + // Act and Assert + var exception = Assert.Throws(() => serviceProvider.GetService()); + exception.Message.ShouldBe("2 handlers for message type JustSaying.IntegrationTests.TestHandlers.OrderPlaced are registered. Only one handler is supported per message type."); + } + } +} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/BlockingHandlerRegistry.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/BlockingHandlerRegistry.cs deleted file mode 100644 index 59682a09a..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/BlockingHandlerRegistry.cs +++ /dev/null @@ -1,14 +0,0 @@ -using JustSaying.IntegrationTests.TestHandlers; -using JustSaying.Messaging.MessageHandling; -using StructureMap; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - public class BlockingHandlerRegistry : Registry - { - public BlockingHandlerRegistry() - { - For>().Singleton().Use(); - } - } -} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/GivenAPublisher.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/GivenAPublisher.cs deleted file mode 100644 index 616227a70..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/GivenAPublisher.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using JustBehave; -using JustSaying.IntegrationTests.TestHandlers; -using JustSaying.Messaging; -using JustSaying.TestingFramework; -using Shouldly; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - public abstract class GivenAPublisher : XAsyncBehaviourTest - { - protected IHaveFulfilledPublishRequirements Publisher { get; set; } - - protected IHaveFulfilledSubscriptionRequirements Subscriber { get; set; } - - protected CancellationTokenSource PublisherCts { get; set; } - protected CancellationTokenSource SubscriberCts { get; set; } - - protected Task DoneSignal { get; set; } - - protected override Task CreateSystemUnderTestAsync() - { - var fixture = new JustSayingFixture(); - - Publisher = fixture.Builder() - .WithSnsMessagePublisher(); - - PublisherCts = new CancellationTokenSource(); - Publisher.StartListening(PublisherCts.Token); - - return Task.FromResult(Publisher); - } - - protected override async Task When() - { - await Publisher.PublishAsync(new OrderPlaced("1234")); - - await WaitForDone(); - - TearDownPubSub(); - } - - private async Task WaitForDone() - { - if (DoneSignal == null) - { - return; - } - - var done = await TaskHelpers.WaitWithTimeoutAsync(DoneSignal); - done.ShouldBe(true, "Done task timed out"); - } - - private void TearDownPubSub() - { - PublisherCts?.Cancel(); - SubscriberCts?.Cancel(); - } - } -} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/MultipleHandlerRegistry.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/MultipleHandlerRegistry.cs deleted file mode 100644 index 91381c97a..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/MultipleHandlerRegistry.cs +++ /dev/null @@ -1,18 +0,0 @@ -using JustSaying.IntegrationTests.TestHandlers; -using JustSaying.Messaging.MessageHandling; -using StructureMap; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - public class MultipleHandlerRegistry : Registry - { - public MultipleHandlerRegistry() - { - For>().Transient().Use() - .Ctor>().Is(new Future()); - - For>().Transient().Use() - .Ctor>().Is(new Future()); - } - } -} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/NamedHandlerResolverTests.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/NamedHandlerResolverTests.cs deleted file mode 100644 index 61e997034..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/NamedHandlerResolverTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Shouldly; -using Xunit; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - [Collection(GlobalSetup.CollectionName)] - public class NamedHandlerResolverTests - { - private readonly IHandlerResolver _handlerResolver = new StructureMapNamedHandlerResolver(); - - [AwsFact] - public void TestQueueAResolution() - { - var context = new HandlerResolutionContext("QueueA"); - var handler = _handlerResolver.ResolveHandler(context); - - handler.ShouldNotBeNull(); - handler.ShouldBeAssignableTo(); - } - - [AwsFact] - public void TestQueueBResolution() - { - var context = new HandlerResolutionContext("QueueB"); - var handler = _handlerResolver.ResolveHandler(context); - - handler.ShouldNotBeNull(); - handler.ShouldBeAssignableTo(); - } - - [AwsFact] - public void TestOtherQueueNameResolution() - { - var context = new HandlerResolutionContext("QueueWithAnyOtherName"); - var handler = _handlerResolver.ResolveHandler(context); - - handler.ShouldNotBeNull(); - handler.ShouldBeAssignableTo(); - } - } -} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/SingleHandlerRegistry.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/SingleHandlerRegistry.cs deleted file mode 100644 index 3e6f87f4d..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/SingleHandlerRegistry.cs +++ /dev/null @@ -1,15 +0,0 @@ -using JustSaying.IntegrationTests.TestHandlers; -using JustSaying.Messaging.MessageHandling; -using StructureMap; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - public class SingleHandlerRegistry : Registry - { - public SingleHandlerRegistry() - { - For>().Singleton().Use() - .Ctor>().Is(new Future()); - } - } -} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/StructureMapHandlerResolver.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/StructureMapHandlerResolver.cs deleted file mode 100644 index f139b8706..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/StructureMapHandlerResolver.cs +++ /dev/null @@ -1,18 +0,0 @@ -using JustSaying.Messaging.MessageHandling; -using StructureMap; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - public class StructureMapHandlerResolver : IHandlerResolver - { - private readonly IContainer _container; - - public StructureMapHandlerResolver(IContainer container) - { - _container = container; - } - - public IHandlerAsync ResolveHandler(HandlerResolutionContext context) - => _container.GetInstance>(); - } -} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/StructuremapNamedHandlerResolver.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/StructuremapNamedHandlerResolver.cs deleted file mode 100644 index 3fb89b6b1..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/StructuremapNamedHandlerResolver.cs +++ /dev/null @@ -1,38 +0,0 @@ -using JustSaying.Messaging.MessageHandling; -using StructureMap; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - public class StructureMapNamedHandlerResolver : IHandlerResolver - { - private readonly IContainer _container; - - public StructureMapNamedHandlerResolver() - { - _container = new Container(ConfigureContainer); - } - - private void ConfigureContainer(ConfigurationExpression config) - { - config.For>() - .Use().Named("QueueA"); - - config.For>() - .Use().Named("QueueB"); - - config.For>() - .Use(); - } - - public IHandlerAsync ResolveHandler(HandlerResolutionContext context) - { - var namedHandler = _container.TryGetInstance>(context.QueueName); - if (namedHandler != null) - { - return namedHandler; - } - - return _container.GetInstance>(); - } - } -} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/TestHandlers.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/TestHandlers.cs deleted file mode 100644 index 13b3dae8c..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/TestHandlers.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Threading.Tasks; -using JustSaying.Messaging.MessageHandling; -using JustSaying.Models; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - public class TestMessage : Message - { - } - - public class HandlerA : IHandlerAsync - { - public Task Handle(TestMessage message) => Task.FromResult(true); - } - - public class HandlerB : IHandlerAsync - { - public Task Handle(TestMessage message) => Task.FromResult(true); - } - - public class HandlerC : IHandlerAsync - { - public Task Handle(TestMessage message) => Task.FromResult(true); - } -} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringAHandlerViaContainerWithMissingRegistration.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringAHandlerViaContainerWithMissingRegistration.cs deleted file mode 100644 index d6fe1fcc4..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringAHandlerViaContainerWithMissingRegistration.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Threading.Tasks; -using JustSaying.IntegrationTests.TestHandlers; -using JustSaying.Messaging.MessageHandling; -using JustSaying.TestingFramework; -using Shouldly; -using StructureMap; -using Xunit; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - [Collection(GlobalSetup.CollectionName)] - public class WhenRegisteringAHandlerViaContainerWithMissingRegistration : GivenAPublisher - { - protected override Task Given() - { - RecordAnyExceptionsThrown(); - return Task.CompletedTask; - } - - protected override Task When() - { - var container = new Container((p) => p.For>().Use()); - - var handlerResolver = new StructureMapHandlerResolver(container); - - var fixture = new JustSayingFixture(); - - fixture.Builder() - .WithSqsTopicSubscriber() - .IntoQueue("container-test") - .WithMessageHandler(handlerResolver); - - return Task.FromResult(true); - } - - [AwsFact] - public void ExceptionIsThrownBecauseHandlerIsNotRegisteredInContainer() - { - ThrownException.ShouldBeAssignableTo(); - } - } -} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringASingleHandlerViaContainer.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringASingleHandlerViaContainer.cs deleted file mode 100644 index 353c4d535..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringASingleHandlerViaContainer.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using JustSaying.IntegrationTests.TestHandlers; -using JustSaying.TestingFramework; -using Shouldly; -using StructureMap; -using Xunit; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - [Collection(GlobalSetup.CollectionName)] - public class WhenRegisteringASingleHandlerViaContainer : GivenAPublisher - { - private Future _handlerFuture; - - protected override Task Given() - { - var container = new Container(x => x.AddRegistry(new SingleHandlerRegistry())); - var resolutionContext = new HandlerResolutionContext("test"); - - var handlerResolver = new StructureMapHandlerResolver(container); - var handler = handlerResolver.ResolveHandler(resolutionContext); - handler.ShouldNotBeNull(); - - _handlerFuture = ((OrderProcessor)handler).Future; - DoneSignal = _handlerFuture.DoneSignal; - - var fixture = new JustSayingFixture(); - - Subscriber = fixture.Builder() - .WithSqsTopicSubscriber() - .IntoQueue("container-test") - .WithMessageHandler(handlerResolver); - - SubscriberCts = new CancellationTokenSource(); - Subscriber.StartListening(SubscriberCts.Token); - - return Task.CompletedTask; - } - - [AwsFact] - public void ThenHandlerWillReceiveTheMessage() - { - _handlerFuture.ReceivedMessageCount.ShouldBeGreaterThan(0); - } - } -} diff --git a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringMultipleHandlersViaContainer.cs b/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringMultipleHandlersViaContainer.cs deleted file mode 100644 index e0af6efc9..000000000 --- a/JustSaying.IntegrationTests/WhenRegisteringHandlersViaResolver/WhenRegisteringMultipleHandlersViaContainer.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Threading.Tasks; -using JustSaying.IntegrationTests.TestHandlers; -using JustSaying.TestingFramework; -using Shouldly; -using StructureMap; -using Xunit; -using Container = StructureMap.Container; - -namespace JustSaying.IntegrationTests.WhenRegisteringHandlersViaResolver -{ - [Collection(GlobalSetup.CollectionName)] - public class WhenRegisteringMultipleHandlersViaContainer : GivenAPublisher - { - private IContainer _container; - - protected override Task Given() - { - RecordAnyExceptionsThrown(); - - _container = new Container(x => x.AddRegistry(new MultipleHandlerRegistry())); - return Task.CompletedTask; - } - - protected override Task When() - { - var handlerResolver = new StructureMapHandlerResolver(_container); - - new JustSayingFixture() - .Builder() - .WithSqsTopicSubscriber() - .IntoQueue("container-test") - .WithMessageHandler(handlerResolver); - - return Task.FromResult(true); - } - - [AwsFact] - public void ThrowsNotSupportedException() - { - ThrownException.ShouldBeAssignableTo(); - } - } -} From 3a0c6d99737c3b1efabaa9c1915e8b437db61619 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 27 Jan 2019 14:04:04 +0000 Subject: [PATCH 4/4] Support custom handler resolver Add functionality to support registering a custom IHandlerResolver service more easily. --- .../WhenUsingCustomHandlerResolver.cs | 66 +++++++++++++++++++ JustSaying/Fluent/ServicesBuilder.cs | 41 ++++++++++++ JustSaying/Fluent/SubscriptionsBuilder.cs | 2 +- JustSaying/MessagingBusBuilder.cs | 10 +-- 4 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenUsingCustomHandlerResolver.cs diff --git a/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenUsingCustomHandlerResolver.cs b/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenUsingCustomHandlerResolver.cs new file mode 100644 index 000000000..ce2310594 --- /dev/null +++ b/JustSaying.IntegrationTests/Fluent/DependencyInjection/Microsoft/WhenUsingCustomHandlerResolver.cs @@ -0,0 +1,66 @@ +using System; +using System.Threading.Tasks; +using JustSaying.IntegrationTests.TestHandlers; +using JustSaying.Messaging; +using JustSaying.Messaging.MessageHandling; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Xunit.Abstractions; + +namespace JustSaying.IntegrationTests.Fluent.DependencyInjection.Microsoft +{ + public class WhenUsingCustomHandlerResolver : IntegrationTestBase + { + public WhenUsingCustomHandlerResolver(ITestOutputHelper outputHelper) + : base(outputHelper) + { + } + + [AwsFact] + public async Task Then_The_Handler_Is_Resolved_From_The_Custom_Resolver() + { + // Arrange + var future = new Future(); + + var services = GivenJustSaying() + .ConfigureJustSaying((builder) => builder.WithLoopbackQueue(UniqueName + "-dispatched")) + .ConfigureJustSaying((builder) => builder.Services((config) => config.WithHandlerResolver(new MyCustomHandlerResolver(future)))); + + await WhenAsync( + services, + async (publisher, listener, cancellationToken) => + { + listener.Start(cancellationToken); + + var message = new OrderPlaced(Guid.NewGuid().ToString()); + + // Act + await publisher.PublishAsync(message, cancellationToken); + + //Assert + await future.DoneSignal; + future.ReceivedMessageCount.ShouldBeGreaterThan(0); + }); + } + + private sealed class MyCustomHandlerResolver : IHandlerResolver + { + internal MyCustomHandlerResolver(Future future) + { + Future = future; + } + + private Future Future { get; } + + public IHandlerAsync ResolveHandler(HandlerResolutionContext context) + { + if (typeof(T) == typeof(OrderPlaced) && context.QueueName.EndsWith("-dispatched", StringComparison.Ordinal)) + { + return new OrderDispatcher(Future) as IHandlerAsync; + } + + throw new NotImplementedException(); + } + } + } +} diff --git a/JustSaying/Fluent/ServicesBuilder.cs b/JustSaying/Fluent/ServicesBuilder.cs index 6b0de0789..9849055c3 100644 --- a/JustSaying/Fluent/ServicesBuilder.cs +++ b/JustSaying/Fluent/ServicesBuilder.cs @@ -23,6 +23,11 @@ internal ServicesBuilder(MessagingBusBuilder busBuilder) /// internal MessagingBusBuilder BusBuilder { get; } + /// + /// Gets or sets a delegate to a method to create the to use. + /// + internal Func HandlerResolver { get; private set; } + /// /// Gets or sets a delegate to a method to create the to use. /// @@ -58,6 +63,42 @@ internal ServicesBuilder(MessagingBusBuilder busBuilder) /// internal Func MessageContextAccessor { get; private set; } + /// + /// Specifies the to use. + /// + /// The to use. + /// + /// The current . + /// + /// + /// is . + /// + public ServicesBuilder WithHandlerResolver(IHandlerResolver handlerResolver) + { + if (handlerResolver == null) + { + throw new ArgumentNullException(nameof(handlerResolver)); + } + + return WithHandlerResolver(() => handlerResolver); + } + + /// + /// Specifies the to use. + /// + /// A delegate to a method to get the to use. + /// + /// The current . + /// + /// + /// is . + /// + public ServicesBuilder WithHandlerResolver(Func handlerResolver) + { + HandlerResolver = handlerResolver ?? throw new ArgumentNullException(nameof(handlerResolver)); + return this; + } + /// /// Specifies the to use. /// diff --git a/JustSaying/Fluent/SubscriptionsBuilder.cs b/JustSaying/Fluent/SubscriptionsBuilder.cs index 97ba8e117..1fae41cf3 100644 --- a/JustSaying/Fluent/SubscriptionsBuilder.cs +++ b/JustSaying/Fluent/SubscriptionsBuilder.cs @@ -156,7 +156,7 @@ public SubscriptionsBuilder ForTopic(Action> conf /// internal void Configure(JustSayingFluently bus) { - var resolver = Parent.ServiceResolver.ResolveService(); + var resolver = Parent.ServicesBuilder?.HandlerResolver?.Invoke() ?? Parent.ServiceResolver.ResolveService(); if (resolver == null) { diff --git a/JustSaying/MessagingBusBuilder.cs b/JustSaying/MessagingBusBuilder.cs index 5a9bb617f..7489d366d 100644 --- a/JustSaying/MessagingBusBuilder.cs +++ b/JustSaying/MessagingBusBuilder.cs @@ -21,6 +21,11 @@ public sealed class MessagingBusBuilder /// internal IServiceResolver ServiceResolver { get; private set; } = new DefaultServiceResolver(); + /// + /// Gets or sets the builder to use for services. + /// + internal ServicesBuilder ServicesBuilder { get; private set; } + /// /// Gets or sets the builder to use for creating an AWS client factory. /// @@ -36,11 +41,6 @@ public sealed class MessagingBusBuilder /// private PublicationsBuilder PublicationsBuilder { get; set; } - /// - /// Gets or sets the builder to use for services. - /// - private ServicesBuilder ServicesBuilder { get; set; } - /// /// Gets or sets the builder to use for subscriptions. ///