diff --git a/src/projects/Routemeister/Dispatchers/AsyncDispatcher.cs b/src/projects/Routemeister/Dispatchers/AsyncDispatcher.cs index e8016f4..7b82741 100644 --- a/src/projects/Routemeister/Dispatchers/AsyncDispatcher.cs +++ b/src/projects/Routemeister/Dispatchers/AsyncDispatcher.cs @@ -40,6 +40,9 @@ public async Task SendAsync(object message) try { var handler = _messageHandlerCreator(action.HandlerType, envelope); + if (handler == null) + throw new InvalidOperationException( + $"Message handler of type {action.HandlerType.FullName} created for message type {action.MessageType.FullName} was null."); var resultingTask = (Task)action.Invoke(handler, envelope.Message); await resultingTask.ConfigureAwait(false); @@ -59,9 +62,19 @@ public async Task PublishAsync(object message) try { - foreach (var action in route.Actions) + var routeActions = route.Actions.Select(a => Tuple.Create(a, _messageHandlerCreator(a.HandlerType, envelope))).ToList(); + foreach (var routeAction in routeActions) { - var handler = _messageHandlerCreator(action.HandlerType, envelope); + var action = routeAction.Item1; + var handler = routeAction.Item2; + if (handler == null) + throw new InvalidOperationException( + $"Message handler of type {action.HandlerType.FullName} created for message type {action.MessageType.FullName} was null."); + } + foreach (var routeAction in routeActions) + { + var action = routeAction.Item1; + var handler = routeAction.Item2; var resultingTask = (Task)action.Invoke(handler, envelope.Message); await resultingTask.ConfigureAwait(false); @@ -92,6 +105,9 @@ public async Task RequestAsync(IRequest request try { var handler = _messageHandlerCreator(action.HandlerType, envelope); + if (handler == null) + throw new InvalidOperationException( + $"Message handler of type {action.HandlerType.FullName} created for message type {action.MessageType.FullName} was null."); var resultingTask = (Task)action.Invoke(handler, envelope.Message); return await resultingTask.ConfigureAwait(false); diff --git a/src/projects/Routemeister/Dispatchers/SyncDispatcher.cs b/src/projects/Routemeister/Dispatchers/SyncDispatcher.cs index 45b088a..0563b04 100644 --- a/src/projects/Routemeister/Dispatchers/SyncDispatcher.cs +++ b/src/projects/Routemeister/Dispatchers/SyncDispatcher.cs @@ -39,6 +39,9 @@ public void Send(object message) try { var handler = _messageHandlerCreator(action.HandlerType, envelope); + if (handler == null) + throw new InvalidOperationException( + $"Message handler of type {action.HandlerType.FullName} created for message type {action.MessageType.FullName} was null."); action.Invoke(handler, envelope.Message); } finally @@ -56,9 +59,19 @@ public void Publish(object message) try { - foreach (var action in route.Actions) + var routeActions = route.Actions.Select(a => Tuple.Create(a, _messageHandlerCreator(a.HandlerType, envelope))).ToList(); + foreach (var routeAction in routeActions) { - var handler = _messageHandlerCreator(action.HandlerType, envelope); + var action = routeAction.Item1; + var handler = routeAction.Item2; + if (handler == null) + throw new InvalidOperationException( + $"Message handler of type {action.HandlerType.FullName} created for message type {action.MessageType.FullName} was null."); + } + foreach (var routeAction in routeActions) + { + var action = routeAction.Item1; + var handler = routeAction.Item2; action.Invoke(handler, envelope.Message); } } @@ -87,6 +100,9 @@ public TResponse Request(IRequest request) try { var handler = _messageHandlerCreator(action.HandlerType, envelope); + if (handler == null) + throw new InvalidOperationException( + $"Message handler of type {action.HandlerType.FullName} created for message type {action.MessageType.FullName} was null."); var result = (TResponse)action.Invoke(handler, envelope.Message); return result; diff --git a/src/projects/Routemeister/Routers/MiddlewareEnabledAsyncRouter.cs b/src/projects/Routemeister/Routers/MiddlewareEnabledAsyncRouter.cs index 59fe7d4..751082b 100644 --- a/src/projects/Routemeister/Routers/MiddlewareEnabledAsyncRouter.cs +++ b/src/projects/Routemeister/Routers/MiddlewareEnabledAsyncRouter.cs @@ -34,28 +34,41 @@ public async Task RouteAsync(T message) var route = _messageRoutes.GetRoute(message.GetType()); var envelope = new MessageEnvelope(message, route.MessageType); + var routeActions = route.Actions.Select(a => Tuple.Create(a, _messageHandlerCreator(a.HandlerType, envelope))).ToList(); + foreach (var routeAction in routeActions) + { + var action = routeAction.Item1; + var handler = routeAction.Item2; + if (handler == null) + throw new InvalidOperationException( + $"Message handler of type {action.HandlerType.FullName} created for message type {action.MessageType.FullName} was null."); + } if (!_middlewares.Any()) - foreach (var action in route.Actions) + { + foreach (var routeAction in routeActions) { - var handler = _messageHandlerCreator(action.HandlerType, envelope); - var resultingTask = (Task)action.Invoke(handler, envelope.Message); - + var action = routeAction.Item1; + var handler = routeAction.Item2; + var resultingTask = (Task) action.Invoke(handler, envelope.Message); await resultingTask.ConfigureAwait(false); } + } else - foreach (var action in route.Actions) + { + foreach (var routeAction in routeActions) { + var action = routeAction.Item1; + var handler = routeAction.Item2; await ProcessAsync( envelope, async e => { - var handler = _messageHandlerCreator(action.HandlerType, envelope); - var resultingTask = (Task)action.Invoke(handler, envelope.Message); - + var resultingTask = (Task) action.Invoke(handler, envelope.Message); await resultingTask.ConfigureAwait(false); } ).ConfigureAwait(false); } + } } private async Task ProcessAsync(MessageEnvelope envelope, Func root) diff --git a/src/projects/Routemeister/Routers/SequentialAsyncRouter.cs b/src/projects/Routemeister/Routers/SequentialAsyncRouter.cs index f841c50..3981ec9 100644 --- a/src/projects/Routemeister/Routers/SequentialAsyncRouter.cs +++ b/src/projects/Routemeister/Routers/SequentialAsyncRouter.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; namespace Routemeister.Routers @@ -32,9 +33,19 @@ public async Task RouteAsync(T message) try { - foreach (var action in route.Actions) + var routeActions = route.Actions.Select(a => Tuple.Create(a, _messageHandlerCreator(a.HandlerType, envelope))).ToList(); + foreach (var routeAction in routeActions) { - var handler = _messageHandlerCreator(action.HandlerType, envelope); + var action = routeAction.Item1; + var handler = routeAction.Item2; + if (handler == null) + throw new InvalidOperationException( + $"Message handler of type {action.HandlerType.FullName} created for message type {action.MessageType.FullName} was null."); + } + foreach (var routeAction in routeActions) + { + var action = routeAction.Item1; + var handler = routeAction.Item2; var resultingTask = (Task)action.Invoke(handler, envelope.Message); await resultingTask.ConfigureAwait(false); diff --git a/src/tests/Routemeister.UnitTests/Dispatchers/AsyncDispatcherTests.cs b/src/tests/Routemeister.UnitTests/Dispatchers/AsyncDispatcherTests.cs index 6498de9..8716691 100644 --- a/src/tests/Routemeister.UnitTests/Dispatchers/AsyncDispatcherTests.cs +++ b/src/tests/Routemeister.UnitTests/Dispatchers/AsyncDispatcherTests.cs @@ -104,6 +104,70 @@ public async Task RequestAsync_Should_invoke_OnBeforeRouting_and_OnAfterRouter_a interceptedMatchingState.Should().BeTrue(); } + [Fact] + public async Task SendAsync_Should_throw_if_created_handler_is_null() + { + var factory = new MessageRouteFactory(); + var routes = new MessageRoutes + { + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IAsyncMessageHandler<>)), + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IAsyncRequestHandler<,>)) + }; + UnitUnderTest = new AsyncDispatcher((t, e) => null, routes); + + var exception = await Assert.ThrowsAsync(() => UnitUnderTest.SendAsync(new ConcreteMessageA())); + + exception.Message.Should().Be($"Message handler of type {typeof(HandlerA).FullName} created for message type {typeof(ConcreteMessageA).FullName} was null."); + } + + [Fact] + public async Task PublishAsync_Should_throw_if_created_handler_is_null() + { + var factory = new MessageRouteFactory(); + var routes = new MessageRoutes + { + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IAsyncMessageHandler<>)), + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IAsyncRequestHandler<,>)) + }; + UnitUnderTest = new AsyncDispatcher((t, e) => t == typeof(HandlerB) ? null : Activator.CreateInstance(t), routes); + + var exception = await Assert.ThrowsAsync(() => UnitUnderTest.PublishAsync(new ConcreteMessageB())); + + exception.Message.Should().Be($"Message handler of type {typeof(HandlerB).FullName} created for message type {typeof(ConcreteMessageB).FullName} was null."); + } + + [Fact] + public async Task PublishAsync_Should_throw_if_other_created_handler_is_null() + { + var factory = new MessageRouteFactory(); + var routes = new MessageRoutes + { + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IAsyncMessageHandler<>)), + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IAsyncRequestHandler<,>)) + }; + UnitUnderTest = new AsyncDispatcher((t, e) => t == typeof(HandlerA) ? null : Activator.CreateInstance(t), routes); + + var exception = await Assert.ThrowsAsync(() => UnitUnderTest.PublishAsync(new ConcreteMessageA())); + + exception.Message.Should().Be($"Message handler of type {typeof(HandlerA).FullName} created for message type {typeof(ConcreteMessageA).FullName} was null."); + } + + [Fact] + public async Task RequestAsync_Should_throw_if_created_handler_is_null() + { + var factory = new MessageRouteFactory(); + var routes = new MessageRoutes + { + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IAsyncMessageHandler<>)), + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IAsyncRequestHandler<,>)) + }; + UnitUnderTest = new AsyncDispatcher((t, e) => null, routes); + + var exception = await Assert.ThrowsAsync(() => UnitUnderTest.RequestAsync(new RequestMessage())); + + exception.Message.Should().Be($"Message handler of type {typeof(HandlerA).FullName} created for message type {typeof(RequestMessage).FullName} was null."); + } + public class ConcreteMessageA { public ConcurrentBag Data { get; } = new ConcurrentBag(); diff --git a/src/tests/Routemeister.UnitTests/Dispatchers/SyncDispatcherTests.cs b/src/tests/Routemeister.UnitTests/Dispatchers/SyncDispatcherTests.cs index 8e75268..f110daa 100644 --- a/src/tests/Routemeister.UnitTests/Dispatchers/SyncDispatcherTests.cs +++ b/src/tests/Routemeister.UnitTests/Dispatchers/SyncDispatcherTests.cs @@ -103,6 +103,70 @@ public void Request_Should_invoke_OnBeforeRouting_and_OnAfterRouter_and_pass_sta interceptedMatchingState.Should().BeTrue(); } + [Fact] + public void SendAsync_Should_throw_if_created_handler_is_null() + { + var factory = new MessageRouteFactory(); + var routes = new MessageRoutes + { + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IMessageHandler<>)), + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IRequestHandler<,>)) + }; + UnitUnderTest = new SyncDispatcher((t, e) => null, routes); + + var exception = Assert.Throws(() => UnitUnderTest.Send(new ConcreteMessageA())); + + exception.Message.Should().Be($"Message handler of type {typeof(HandlerA).FullName} created for message type {typeof(ConcreteMessageA).FullName} was null."); + } + + [Fact] + public void PublishAsync_Should_throw_if_created_handler_is_null() + { + var factory = new MessageRouteFactory(); + var routes = new MessageRoutes + { + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IMessageHandler<>)), + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IRequestHandler<,>)) + }; + UnitUnderTest = new SyncDispatcher((t, e) => t == typeof(HandlerB) ? null : Activator.CreateInstance(t), routes); + + var exception = Assert.Throws(() => UnitUnderTest.Publish(new ConcreteMessageB())); + + exception.Message.Should().Be($"Message handler of type {typeof(HandlerB).FullName} created for message type {typeof(ConcreteMessageB).FullName} was null."); + } + + [Fact] + public void PublishAsync_Should_throw_if_other_created_handler_is_null() + { + var factory = new MessageRouteFactory(); + var routes = new MessageRoutes + { + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IMessageHandler<>)), + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IRequestHandler<,>)) + }; + UnitUnderTest = new SyncDispatcher((t, e) => t == typeof(HandlerA) ? null : Activator.CreateInstance(t), routes); + + var exception = Assert.Throws(() => UnitUnderTest.Publish(new ConcreteMessageA())); + + exception.Message.Should().Be($"Message handler of type {typeof(HandlerA).FullName} created for message type {typeof(ConcreteMessageA).FullName} was null."); + } + + [Fact] + public void RequestAsync_Should_throw_if_created_handler_is_null() + { + var factory = new MessageRouteFactory(); + var routes = new MessageRoutes + { + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IMessageHandler<>)), + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IRequestHandler<,>)) + }; + UnitUnderTest = new SyncDispatcher((t, e) => null, routes); + + var exception = Assert.Throws(() => UnitUnderTest.Request(new RequestMessage())); + + exception.Message.Should().Be($"Message handler of type {typeof(HandlerA).FullName} created for message type {typeof(RequestMessage).FullName} was null."); + } + public class ConcreteMessageA { public ConcurrentBag Data { get; } = new ConcurrentBag(); diff --git a/src/tests/Routemeister.UnitTests/Routers/MiddlewareEnabledAsyncRouterTests.cs b/src/tests/Routemeister.UnitTests/Routers/MiddlewareEnabledAsyncRouterTests.cs index 2428a3c..189b572 100644 --- a/src/tests/Routemeister.UnitTests/Routers/MiddlewareEnabledAsyncRouterTests.cs +++ b/src/tests/Routemeister.UnitTests/Routers/MiddlewareEnabledAsyncRouterTests.cs @@ -164,6 +164,21 @@ public async Task Should_be_able_to_pass_envelope_state() "MW2 in MW1 is 'MW2 of ConcreteMessageB'"); } + [Fact] + public async Task Should_throw_if_created_handler_is_null() + { + var factory = new MessageRouteFactory(); + var routes = new MessageRoutes + { + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IHandle<>)) + }; + UnitUnderTest = new MiddlewareEnabledAsyncRouter((t, e) => null, routes); + + var exception = await Assert.ThrowsAsync(() => UnitUnderTest.RouteAsync(new ConcreteMessageA())); + + exception.Message.Should().Be($"Message handler of type {typeof(HandlerA).FullName} created for message type {typeof(ConcreteMessageA).FullName} was null."); + } + public interface IHandle { Task HandleAsync(T message); diff --git a/src/tests/Routemeister.UnitTests/Routers/SequentialAsyncRouterTests.cs b/src/tests/Routemeister.UnitTests/Routers/SequentialAsyncRouterTests.cs index 6b12498..f29578e 100644 --- a/src/tests/Routemeister.UnitTests/Routers/SequentialAsyncRouterTests.cs +++ b/src/tests/Routemeister.UnitTests/Routers/SequentialAsyncRouterTests.cs @@ -56,6 +56,21 @@ public async Task Should_invoke_OnBeforeRouting_and_OnAfterRouter_and_pass_state interceptedMatchingState.Should().BeTrue(); } + [Fact] + public async Task Should_throw_if_created_handler_is_null() + { + var factory = new MessageRouteFactory(); + var routes = new MessageRoutes + { + factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IHandle<>)) + }; + UnitUnderTest = new SequentialAsyncRouter((t, e) => null, routes); + + var exception = await Assert.ThrowsAsync(() => UnitUnderTest.RouteAsync(new ConcreteMessageA())); + + exception.Message.Should().Be($"Message handler of type {typeof(HandlerA).FullName} created for message type {typeof(ConcreteMessageA).FullName} was null."); + } + public interface IHandle { Task HandleAsync(T message);