From 208d8924615160fadc6a193b717ae4c6d86d8625 Mon Sep 17 00:00:00 2001 From: Konrad Plazinski Date: Mon, 16 Mar 2026 10:44:11 +0100 Subject: [PATCH] Prevent dispatch when Service Bus is disabled Added checks to ensure no messages are sent when the Service Bus is disabled. Included tests to verify correct behavior and updated the changelog. --- docs/CHANGELOG.md | 4 + src/Ev.ServiceBus/Dispatch/DispatchSender.cs | 14 ++ tests/Ev.ServiceBus.UnitTests/DispatchTest.cs | 171 ++++++++++++++++++ 3 files changed, 189 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b4c50fc..9532d52 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 5.6.1 +- fixed + - Fixed an issue with dispatching messages when the Enabled flag is set to false. + ## 5.6.0 - Added - netstandard2.0 target framework. diff --git a/src/Ev.ServiceBus/Dispatch/DispatchSender.cs b/src/Ev.ServiceBus/Dispatch/DispatchSender.cs index 480402a..ed5c570 100644 --- a/src/Ev.ServiceBus/Dispatch/DispatchSender.cs +++ b/src/Ev.ServiceBus/Dispatch/DispatchSender.cs @@ -42,6 +42,8 @@ public DispatchSender( /// public async Task SendDispatch(object messagePayload, CancellationToken token = default) { + if (IsDisabled()) return; + var dispatch = new Abstractions.Dispatch(messagePayload); await SendDispatch(dispatch, token); @@ -50,6 +52,8 @@ public async Task SendDispatch(object messagePayload, CancellationToken token = /// public async Task SendDispatch(Abstractions.Dispatch messagePayload, CancellationToken token = default) { + if (IsDisabled()) return; + var dispatches = CreateMessagesToSend([messagePayload]); foreach (var messagePerResource in dispatches) @@ -74,6 +78,8 @@ public async Task SendDispatches(IEnumerable messagePayloads, Cancellati throw new ArgumentNullException(nameof(messagePayloads)); } + if (IsDisabled()) return; + var dispatches = messagePayloads.Select(o => new Abstractions.Dispatch(o)).ToArray(); await SendDispatches(dispatches, token); } @@ -86,6 +92,8 @@ public async Task SendDispatches(IEnumerable messagePaylo throw new ArgumentNullException(nameof(messagePayloads)); } + if (IsDisabled()) return; + var dispatches = CreateMessagesToSend(messagePayloads); foreach (var messagesPerResource in dispatches) { @@ -139,6 +147,8 @@ public async Task ScheduleDispatches(IEnumerable messagePayloads, DateTi throw new ArgumentNullException(nameof(messagePayloads)); } + if (IsDisabled()) return; + var dispatches = messagePayloads.Select(o => new Abstractions.Dispatch(o)).ToArray(); await ScheduleDispatches(dispatches, scheduledEnqueueTime, token); } @@ -151,6 +161,8 @@ public async Task ScheduleDispatches(IEnumerable messageP throw new ArgumentNullException(nameof(messagePayloads)); } + if (IsDisabled()) return; + var dispatches = CreateMessagesToSend(messagePayloads); foreach (var messagesPerResource in dispatches) { @@ -279,4 +291,6 @@ private ServiceBusMessage CreateMessage( } return message; } + + private bool IsDisabled() => _serviceBusOptions.Settings.Enabled == false; } \ No newline at end of file diff --git a/tests/Ev.ServiceBus.UnitTests/DispatchTest.cs b/tests/Ev.ServiceBus.UnitTests/DispatchTest.cs index 1009089..2111954 100644 --- a/tests/Ev.ServiceBus.UnitTests/DispatchTest.cs +++ b/tests/Ev.ServiceBus.UnitTests/DispatchTest.cs @@ -582,6 +582,159 @@ public async Task ShouldAssignIsolationKeyWhenInIsolationMode() _sentMessagesToQueue[0].ApplicationProperties.GetIsolationKey().Should().Be(isolationKey); } + [Fact] + public async Task SendDispatch_Object_WhenDisabled_DoesNotInvokeSender() + { + var provider = await CreateDisabledProviderAsync(); + + using (var scope = provider.CreateScope()) + { + var sender = scope.ServiceProvider.GetRequiredService(); + await sender.SendDispatch((object)new SubscribedEvent { SomeNumber = 1, SomeString = "test" }); + } + + provider.GetRequiredService().GetSenderMock("myQueue").Should().BeNull(); + await provider.SimulateStopHost(CancellationToken.None); + } + + [Fact] + public async Task SendDispatch_Dispatch_WhenDisabled_DoesNotInvokeSender() + { + var provider = await CreateDisabledProviderAsync(); + + using (var scope = provider.CreateScope()) + { + var sender = scope.ServiceProvider.GetRequiredService(); + await sender.SendDispatch(new Ev.ServiceBus.Abstractions.Dispatch(new SubscribedEvent { SomeNumber = 1, SomeString = "test" })); + } + + provider.GetRequiredService().GetSenderMock("myQueue").Should().BeNull(); + await provider.SimulateStopHost(CancellationToken.None); + } + + [Fact] + public async Task SendDispatches_Objects_WhenDisabled_DoesNotInvokeSender() + { + var provider = await CreateDisabledProviderAsync(); + + using (var scope = provider.CreateScope()) + { + var sender = scope.ServiceProvider.GetRequiredService(); + await sender.SendDispatches(new object[] { new SubscribedEvent { SomeNumber = 1, SomeString = "test" } }); + } + + provider.GetRequiredService().GetSenderMock("myQueue").Should().BeNull(); + await provider.SimulateStopHost(CancellationToken.None); + } + + [Fact] + public async Task SendDispatches_Dispatches_WhenDisabled_DoesNotInvokeSender() + { + var provider = await CreateDisabledProviderAsync(); + + using (var scope = provider.CreateScope()) + { + var sender = scope.ServiceProvider.GetRequiredService(); + await sender.SendDispatches(new[] { new Ev.ServiceBus.Abstractions.Dispatch(new SubscribedEvent { SomeNumber = 1, SomeString = "test" }) }); + } + + provider.GetRequiredService().GetSenderMock("myQueue").Should().BeNull(); + await provider.SimulateStopHost(CancellationToken.None); + } + + [Fact] + public async Task ScheduleDispatches_Objects_WhenDisabled_DoesNotInvokeSender() + { + var provider = await CreateDisabledProviderAsync(); + + using (var scope = provider.CreateScope()) + { + var sender = scope.ServiceProvider.GetRequiredService(); + await sender.ScheduleDispatches( + new object[] { new SubscribedEvent { SomeNumber = 1, SomeString = "test" } }, + DateTimeOffset.UtcNow.AddDays(1)); + } + + provider.GetRequiredService().GetSenderMock("myQueue").Should().BeNull(); + await provider.SimulateStopHost(CancellationToken.None); + } + + [Fact] + public async Task ScheduleDispatches_Dispatches_WhenDisabled_DoesNotInvokeSender() + { + var provider = await CreateDisabledProviderAsync(); + + using (var scope = provider.CreateScope()) + { + var sender = scope.ServiceProvider.GetRequiredService(); + await sender.ScheduleDispatches( + new[] { new Ev.ServiceBus.Abstractions.Dispatch(new SubscribedEvent { SomeNumber = 1, SomeString = "test" }) }, + DateTimeOffset.UtcNow.AddDays(1)); + } + + provider.GetRequiredService().GetSenderMock("myQueue").Should().BeNull(); + await provider.SimulateStopHost(CancellationToken.None); + } + + // Null-argument checks must fire before IsDisabled() for all overloads that own them + [Fact] + public async Task SendDispatches_Objects_WhenDisabled_NullPayload_ThrowsArgumentNullException() + { + var provider = await CreateDisabledProviderAsync(); + + using (var scope = provider.CreateScope()) + { + var sender = scope.ServiceProvider.GetRequiredService(); + await Assert.ThrowsAsync(() => sender.SendDispatches((IEnumerable)null!)); + } + + await provider.SimulateStopHost(CancellationToken.None); + } + + [Fact] + public async Task SendDispatches_Dispatches_WhenDisabled_NullPayload_ThrowsArgumentNullException() + { + var provider = await CreateDisabledProviderAsync(); + + using (var scope = provider.CreateScope()) + { + var sender = scope.ServiceProvider.GetRequiredService(); + await Assert.ThrowsAsync(() => sender.SendDispatches((IEnumerable)null!)); + } + + await provider.SimulateStopHost(CancellationToken.None); + } + + [Fact] + public async Task ScheduleDispatches_Objects_WhenDisabled_NullPayload_ThrowsArgumentNullException() + { + var provider = await CreateDisabledProviderAsync(); + + using (var scope = provider.CreateScope()) + { + var sender = scope.ServiceProvider.GetRequiredService(); + await Assert.ThrowsAsync(() => + sender.ScheduleDispatches((IEnumerable)null!, DateTimeOffset.UtcNow.AddDays(1))); + } + + await provider.SimulateStopHost(CancellationToken.None); + } + + [Fact] + public async Task ScheduleDispatches_Dispatches_WhenDisabled_NullPayload_ThrowsArgumentNullException() + { + var provider = await CreateDisabledProviderAsync(); + + using (var scope = provider.CreateScope()) + { + var sender = scope.ServiceProvider.GetRequiredService(); + await Assert.ThrowsAsync(() => + sender.ScheduleDispatches((IEnumerable)null!, DateTimeOffset.UtcNow.AddDays(1))); + } + + await provider.SimulateStopHost(CancellationToken.None); + } + private void GivenIsolationKeyInMetadata(string isolationKey) { var appProperties = new Dictionary { { UserProperties.IsolationKey , isolationKey } }; @@ -601,6 +754,24 @@ private ServiceBusMessage GetMessageFrom(string clientToCheck) return _sentMessagesToQueue.FirstOrDefault(); } + private static async Task CreateDisabledProviderAsync() + { + var services = new ServiceCollection(); + services.AddServiceBus(settings => + { + settings.Enabled = false; + settings.WithConnection("Endpoint=testConnectionString;", new ServiceBusClientOptions()); + }); + services.OverrideClientFactory(); + services.RegisterServiceBusDispatch().ToQueue("myQueue", builder => + { + builder.RegisterDispatch(); + }); + var provider = services.BuildServiceProvider(); + await provider.SimulateStartHost(CancellationToken.None); + return provider; + } + public void Dispose() { _composer?.Dispose();