A lightweight in-process, delegate-based message handling library.
Branch | Status |
---|---|
Master | |
Dev |
This library is developed with a goal to help developers speed up the development of applications by minimizing boilerplates in the code. No message marker interfaces, no message handler interfaces, no pipelines, etc - just define a message class, hook up delegates, and you're good to go!
This makes the library suitable for building prototypes/proof of concept applications, but at the same time, also serve as a lightweight base for your own messaging infrastructure.
You can simply clone this repository, build the source, reference the output dll, and code away!
The library has also been published as a Nuget package:
To install Nuget package:
- Open command prompt
- Go to project directory
- Add the package to the project:
dotnet add package Xer.Delegator
- Restore the packages:
dotnet restore
The samples follows the CQRS pattern so you will see commands, events, etc.
// Startup.cs
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
// Register message handler resolver to the container.
// This is resolved by the MessageDelegator.
services.AddSingleton<IMessageHandlerResolver>((serviceProvider) =>
{
// Commands can only have one handler so use SingleMessageHandlerRegistration.
var commandHandlerRegistration = new SingleMessageHandlerRegistration();
// Register command handlers to the single message handler registration.
// ActivateProductCommand
commandHandlerRegistration.Register<RegisterProductCommand>((message, cancellationToken) =>
{
// You can also manually instantiate if that's how you roll.
var handler = serviceProvider.GetRequiredService<RegisterProductCommandHandler>();
return handler.HandleRegisterProductCommandAsync(message, cancellationToken);
});
// ActivateProductCommand
commandHandlerRegistration.Register<ActivateProductCommand>((message, cancellationToken) =>
{
// You can also manually instantiate if that's how you roll.
var handler = serviceProvider.GetRequiredService<ActivateProductCommandHandler>();
return handler.HandleActivateProductCommandAsync(message, cancellationToken);
});
// DeactivateProductCommand
commandHandlerRegistration.Register<DeactivateProductCommand>((message, cancellationToken) =>
{
// You can also manually instantiate if that's how you roll.
var handler = serviceProvider.GetRequiredService<DeactivateProductCommandHandler>();
return handler.HandleDeactivateProductCommandAsync(message, cancellationToken);
});
return commandHandlerRegistration.BuildMessageHandlerResolver();
});
// Register message delegator to the container.
// This can be simply be: services.AddSingleton<IMessageDelegator, MessageDelegator>(),
// but I wanted to clearly show that MessageDelegator depends on IMessageHandlerResolver.
services.AddSingleton<IMessageDelegator, MessageDelegator>((serviceProvider) =>
// Get the registered instance of IMessageHandlerResolver shown above.
new MessageDelegator(serviceProvider.GetRequiredService<IMessageHandlerResolver>())
);
...
}
// Startup.cs
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
// Register message handler resolver to the container.
// This is resolved by the MessageDelegator.
services.AddSingleton<IMessageHandlerResolver>((serviceProvider) =>
{
// Events can have multiple handlers so use MultiMessageHandlerRegistration.
var eventHandlerRegistration = new MultiMessageHandlerRegistration();
// Register event handlers to the message handler registration.
// ProductRegisteredEvent
eventHandlerRegistration.Register<ProductRegisteredEvent>((message, cancellationToken) =>
{
// You can also manually instantiate if that's how you roll.
var handler = serviceProvider.GetRequiredService<ProductDomainEventsHandler>();
return handler.HandleProductRegisteredEventAsync(message, cancellationToken);
});
// ProductActivatedEvent
eventHandlerRegistration.Register<ProductActivatedEvent>((message, cancellationToken) =>
{
// You can also manually instantiate if that's how you roll.
var handler = serviceProvider.GetRequiredService<ProductDomainEventsHandler>();
return handler.HandleProductActivatedEventAsync(message, cancellationToken);
});
// ProductDeactivatedEvent
eventHandlerRegistration.Register<ProductDeactivatedEvent>((message, cancellationToken) =>
{
// You can also manually instantiate if that's how you roll.
var handler = serviceProvider.GetRequiredService<ProductDomainEventsHandler>();
return handler.HandleProductDeactivatedEventAsync(message, cancellationToken);
});
return eventHandlerRegistration.BuildMessageHandlerResolver();
});
// Register message delegator to the container.
// This can be simply be: services.AddSingleton<IMessageDelegator, MessageDelegator>(),
// but I wanted to clearly show that MessageDelegator depends on IMessageHandlerResolver.
services.AddSingleton<IMessageDelegator, MessageDelegator>((serviceProvider) =>
// Get the registered instance of IMessageHandlerResolver shown above.
new MessageDelegator(serviceProvider.GetRequiredService<IMessageHandlerResolver>())
);
...
}
All messages can be delegated to one or more message handlers through the MessageDelegator's SendAsync API.
// ProductController.cs
private readonly IMessageDelegator _messageDelegator;
public ProductController(IMessageDelegator messageDelegator)
{
_messageDelegator = messageDelegator;
}
[HttpPost]
public async Task<IActionResult> RegisterProduct([FromBody]RegisterProductCommandDto model)
{
// Convert DTO to domain command.
RegisterProductCommand command = model.ToDomainCommand();
// Send command message to handler.
await _messageDelegator.SendAsync(command);
return Ok();
}