Skip to content

Commit

Permalink
Don't throw error if no handlers were found for plain event message t…
Browse files Browse the repository at this point in the history
…ypes
  • Loading branch information
litenova committed May 2, 2024
1 parent 4218437 commit b2f6693
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 15 deletions.
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## v.0.24.3
- Don't throw error by default if no handlers were found for plain event message types

## v.0.24.2
- Allow aborting the execution of handlers by calling `Abort` on the execution context.

Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<LangVersion>latest</LangVersion>
<Authors>A. Shafie</Authors>
<PackageTags>mediator;cqrs</PackageTags>
<VersionPrefix>0.24.2</VersionPrefix>
<VersionPrefix>0.24.3</VersionPrefix>
<PackageIcon>icon.png</PackageIcon>
<Description>LiteBus is an easy-to-use and ambitious in-process mediator providing the foundation to implement Command Query Separation (CQS). It is implemented with minimal reflection and instead utilizes covariance and contravariance to provide its core functionality.</Description>
<PackageProjectUrl>https://github.com/litenova/LiteBus</PackageProjectUrl>
Expand Down
6 changes: 4 additions & 2 deletions src/LiteBus.Events/EventMediator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public Task PublishAsync(IEvent @event, EventMediationSettings? eventMediationSe
MessageMediationStrategy = mediationStrategy,
MessageResolveStrategy = resolveStrategy,
CancellationToken = cancellationToken,
Tags = eventMediationSettings.Filters.Tags
Tags = eventMediationSettings.Filters.Tags,
RegisterPlainMessagesOnSpot = !eventMediationSettings.ThrowIfNoHandlerFound
});
}

Expand All @@ -46,7 +47,8 @@ public Task PublishAsync(IEvent @event, EventMediationSettings? eventMediationSe
MessageMediationStrategy = mediationStrategy,
MessageResolveStrategy = resolveStrategy,
CancellationToken = cancellationToken,
Tags = eventMediationSettings.Filters.Tags
Tags = eventMediationSettings.Filters.Tags,
RegisterPlainMessagesOnSpot = !eventMediationSettings.ThrowIfNoHandlerFound
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
namespace LiteBus.Messaging.Abstractions;

[Serializable]
internal class MessageNotRegisteredException : Exception
public class NoHandlerFoundException : Exception
{
public MessageNotRegisteredException(Type messageType) :
base($"The message type '{messageType.Name}' is not registered")
public NoHandlerFoundException(Type messageType) : base($"No handler found for message type '{messageType.Name}'")
{
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
#nullable enable
using System;
using System.Linq;

namespace LiteBus.Messaging.Abstractions;

public sealed class ActualTypeOrFirstAssignableTypeMessageResolveStrategy : IMessageResolveStrategy
{
public IMessageDescriptor Find(Type messageType, IMessageRegistry messageRegistry)
public IMessageDescriptor? Find(Type messageType, IMessageRegistry messageRegistry)
{
if (messageType.IsGenericType)
{
Expand All @@ -15,11 +16,6 @@ public IMessageDescriptor Find(Type messageType, IMessageRegistry messageRegistr
var descriptor = messageRegistry.SingleOrDefault(d => d.MessageType == messageType) ??
messageRegistry.FirstOrDefault(d => d.MessageType.IsAssignableFrom(messageType));

if (descriptor is null)
{
throw new MessageNotRegisteredException(messageType);
}

return descriptor;
}
}
5 changes: 3 additions & 2 deletions src/LiteBus.Messaging.Abstractions/IMessageResolveStrategy.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using System;
#nullable enable
using System;

namespace LiteBus.Messaging.Abstractions;

public interface IMessageResolveStrategy
{
IMessageDescriptor Find(Type messageType, IMessageRegistry messageRegistry);
IMessageDescriptor? Find(Type messageType, IMessageRegistry messageRegistry);
}
8 changes: 8 additions & 0 deletions src/LiteBus.Messaging.Abstractions/MediateOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,12 @@ public sealed class MediateOptions<TMessage, TMessageResult>

// TODO: temporary placement for tags. Need to find a better place
public required IEnumerable<string> Tags { get; init; }

/// <summary>
/// Indicates whether to register plain messages on spot. Plain messages are messages that do not implement any interfaces.
/// </summary>
/// <remarks>
///
/// </remarks>
public bool RegisterPlainMessagesOnSpot { get; init; } = false;
}
13 changes: 13 additions & 0 deletions src/LiteBus.Messaging/Internal/Mediator/MessageMediator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ internal sealed class MessageMediator : IMessageMediator
// Find the message descriptor
var descriptor = options.MessageResolveStrategy.Find(messageType, _messageRegistry);

if (descriptor is null)
{
if (!options.RegisterPlainMessagesOnSpot)
{
throw new NoHandlerFoundException(messageType);
}
else
{
_messageRegistry.Register(messageType);
descriptor = options.MessageResolveStrategy.Find(messageType, _messageRegistry);
}
}

// resolve the dependencies in lazy mode
var messageDependencies = new MessageDependencies(messageType, descriptor, _serviceProvider, options.Tags);

Expand Down
48 changes: 48 additions & 0 deletions tests/LiteBus.Events.UnitTests/EventModuleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
using LiteBus.Events.Abstractions;
using LiteBus.Events.Extensions.MicrosoftDependencyInjection;
using LiteBus.Events.UnitTests.UseCases;
using LiteBus.Events.UnitTests.UseCases.EventWithNoHandlers;
using LiteBus.Events.UnitTests.UseCases.EventWithTag;
using LiteBus.Events.UnitTests.UseCases.ProblematicEvent;
using LiteBus.Events.UnitTests.UseCases.ProductCreated;
using LiteBus.Events.UnitTests.UseCases.ProductUpdated;
using LiteBus.Events.UnitTests.UseCases.ProductViewed;
using LiteBus.Messaging.Abstractions;
using LiteBus.Messaging.Extensions.MicrosoftDependencyInjection;
using Microsoft.Extensions.DependencyInjection;

Expand Down Expand Up @@ -279,4 +281,50 @@ public async Task mediating_the_an_event_with_both_all_available_tags_goes_throu
@event.ExecutedTypes[8].Should().Be<EventWithTagEventHandlerPostHandler2>();
@event.ExecutedTypes[9].Should().Be<GlobalEventPostHandler>();
}

[Fact]
public async Task mediating_the_an_event_with_no_handlers_should_not_throw_exception_when_ThrowIfNoHandlerFound_is_set_false()
{
var serviceProvider = new ServiceCollection()
.AddLiteBus(configuration => { configuration.AddEventModule(builder => { builder.RegisterFromAssembly(typeof(ProblematicEventPreHandler).Assembly); }); })
.BuildServiceProvider();

var eventMediator = serviceProvider.GetRequiredService<IEventMediator>();

var @event = new EventWithNoHandlers();

var settings = new EventMediationSettings
{
ThrowIfNoHandlerFound = false,
};

// Act
await eventMediator.PublishAsync(@event, settings);

// Assert
@event.ExecutedTypes.Should().HaveCount(0);
}

[Fact]
public async Task mediating_the_an_event_with_no_handlers_should_throw_exception_when_ThrowIfNoHandlerFound_is_set_true()
{
var serviceProvider = new ServiceCollection()
.AddLiteBus(configuration => { configuration.AddEventModule(builder => { builder.RegisterFromAssembly(typeof(ProblematicEventPreHandler).Assembly); }); })
.BuildServiceProvider();

var eventMediator = serviceProvider.GetRequiredService<IEventMediator>();

var @event = new EventWithNoHandlers();

var settings = new EventMediationSettings
{
ThrowIfNoHandlerFound = true,
};

// Act
var act = () => eventMediator.PublishAsync(@event, settings);

// Assert
await act.Should().ThrowAsync<NoHandlerFoundException>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace LiteBus.Events.UnitTests.UseCases.EventWithNoHandlers;

public class EventWithNoHandlers
{
public List<Type> ExecutedTypes { get; } = new();
}

0 comments on commit b2f6693

Please sign in to comment.