Skip to content

Commit 18bc777

Browse files
committed
[Host.Memory] Let the .AutoDeclareFrom() also register services in MSDI + update docs
Signed-off-by: Tomasz Maruszak <maruszaktomasz@gmail.com>
1 parent 61046e7 commit 18bc777

40 files changed

+822
-772
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ The configuration can be [modularized](docs/intro.md#modularization-of-configura
137137
- [Transactional Outbox](docs/plugin_outbox.md)
138138
- [Validation using FluentValidation](docs/plugin_fluent_validation.md)
139139
- [AsyncAPI specification generation](docs/plugin_asyncapi.md)
140+
- [Consumer Circuit Breaker](docs/intro.md#health-check-circuit-breaker)
140141
- [Samples](src/Samples/README.md)
141142
- [Use Cases](docs/UseCases/)
142143

docs/NuGet.md

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,25 @@
1-
# SlimMessageBus
1+
**SlimMessageBus** is a lightweight and extensible message bus framework for .NET, designed to simplify working with message brokers and in-process messaging.
22

3-
SlimMessageBus is a client façade for message brokers for .NET.
4-
It comes with implementations for specific brokers and in-memory message passing (in-process communication).
5-
SlimMessageBus additionally provides request-response implementation over message queues, and many other plugins.
3+
It supports a variety of transport providers and offers built-in patterns like publish/subscribe and request/response over queues.
64

7-
Transports:
5+
### Supported Transports
6+
- Amazon SQS/SNS
7+
- Apache Kafka
8+
- Azure Event Hub
9+
- Azure Service Bus
10+
- Hybrid (combine multiple transports)
11+
- In-memory (for domain events and mediator-style messaging)
12+
- MQTT / Azure IoT Hub
13+
- NATS
14+
- RabbitMQ
15+
- Redis
16+
- SQL (MS SQL)
817

9-
- Amazon SQS/SNS
10-
- Apache Kafka
11-
- Azure Event Hub
12-
- Azure Service Bus
13-
- Hybrid (composition of the bus out of many transports)
14-
- In-Memory transport (domain events, mediator)
15-
- MQTT / Azure IoT Hub
16-
- NATS
17-
- RabbitMQ
18-
- Redis
19-
- SQL (MS SQL, PostgreSql)
18+
### Available Plugins
19+
- **FluentValidation** for message validation
20+
- **Transactional Outbox** pattern (supports SQL and DbContext)
21+
- **Serialization** with JSON, Avro, or ProtoBuf
22+
- **AsyncAPI** spec generation
23+
- **Consumer Circuit Breaker** with Health Checks integration
2024

21-
Plugins:
22-
23-
- Message validation via Fluent Validation
24-
- Transactional Outbox pattern (SQL, DbContext)
25-
- Serialization using JSON, Avro, ProtoBuf
26-
- AsyncAPI specification generation
27-
- Consumer Circuit Breaker based on Health Checks
28-
29-
Find out more [https://github.com/zarusz/SlimMessageBus](https://github.com/zarusz/SlimMessageBus).
25+
For full documentation and examples, visit the [GitHub repository](https://github.com/zarusz/SlimMessageBus).

docs/UseCases/ReplaceMediatR.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,7 @@ var builder = WebApplication.CreateBuilder(args);
7272
// Configure SlimMessageBus with In-Memory provider
7373
builder.Services.AddSlimMessageBus(mbb =>
7474
{
75-
mbb
76-
.WithProviderMemory()
77-
.AutoDeclareFrom(typeof(Program).Assembly)
78-
.AddServicesFromAssemblyContaining<Program>();
75+
mbb.WithProviderMemory().AutoDeclareFrom(typeof(Program).Assembly);
7976
});
8077

8178
var app = builder.Build();
@@ -115,3 +112,6 @@ public class PingRequestHandler : IRequestHandler<PingRequest, string>
115112
- **Hybrid Messaging**: Seamlessly transition from in-memory to out-of-process messaging if your application evolves (or combine both).
116113

117114
For more advanced usage and additional features, please review the [SlimMessageBus documentation](/docs/).
115+
- **Hybrid Messaging**: Seamlessly transition from in-memory to out-of-process messaging if your application evolves (or combine both).
116+
117+
For more advanced usage and additional features, please review the [SlimMessageBus documentation](/docs/).

docs/plugin_fluent_validation.md

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,23 @@ Please read the [Introduction](intro.md) before reading this provider documentat
1515
The [`SlimMessageBus.Host.FluentValidation`](https://www.nuget.org/packages/SlimMessageBus.Host.FluentValidation) introduces validation on the producer or consumer side by leveraging the [FluentValidation](https://www.nuget.org/packages/FluentValidation) library.
1616
The plugin is based on [`SlimMessageBus.Host.Interceptor`](https://www.nuget.org/packages/SlimMessageBus.Host.Interceptor) core interfaces and can work with any transport including the memory bus.
1717

18+
See the [full sample](/src/Samples/Sample.ValidatingWebApi/).
19+
1820
## Configuration
1921

2022
Consider the following command, with the validator (using FluentValidation) and command handler:
2123

2224
```cs
23-
// The command
24-
public record CreateCustomerCommand : IRequest<CommandResultWithId>
25+
public record CreateCustomerCommand : IRequest<CreateCustomerCommandResult>
2526
{
2627
public string? FirstName { get; set; }
2728
public string? LastName { get; set; }
2829
public string? Email { get; set; }
2930
public string? Phone { get; set; }
3031
}
32+
```
3133

32-
// The validator of the command (using FluentValidation)
34+
```cs
3335
public class CreateCustomerCommandValidator : AbstractValidator<CreateCustomerCommand>
3436
{
3537
public CreateCustomerCommandValidator()
@@ -40,13 +42,14 @@ public class CreateCustomerCommandValidator : AbstractValidator<CreateCustomerCo
4042
RuleFor(x => x.Phone).NotEmpty().Length(6).When(x => x.Phone != null);
4143
}
4244
}
45+
```
4346

44-
// The handler of the command
45-
public class CreateCustomerCommandHandler : IRequestHandler<CreateCustomerCommand, CommandResultWithId>
47+
```cs
48+
public class CreateCustomerCommandHandler : IRequestHandler<CreateCustomerCommand, CreateCustomerCommandResult>
4649
{
47-
public async Task<CommandResultWithId> OnHandle(CreateCustomerCommand command)
50+
public Task<CreateCustomerCommandResult> OnHandle(CreateCustomerCommand command, CancellationToken cancellationToken)
4851
{
49-
// ...
52+
return Task.FromResult(new CreateCustomerCommandResult(Guid.NewGuid()));
5053
}
5154
}
5255
```
@@ -56,30 +59,29 @@ public class CreateCustomerCommandHandler : IRequestHandler<CreateCustomerComman
5659
Consider an in-process command that is delivered using the memory bus:
5760

5861
```cs
59-
// Using minimal APIs
6062
var builder = WebApplication.CreateBuilder(args);
6163

62-
// Configure SMB
63-
builder.Services.AddSlimMessageBus(mbb =>
64-
{
65-
mbb
66-
.WithProviderMemory()
64+
builder.Services.AddSlimMessageBus(mbb => mbb
65+
.WithProviderMemory()
6766
.AutoDeclareFrom(Assembly.GetExecutingAssembly())
68-
.AddServicesFromAssembly(Assembly.GetExecutingAssembly())
69-
.AddFluentValidation(opts =>
70-
{
71-
// SMB FluentValidation setup goes here
72-
});
73-
});
67+
.AddAspNet()
68+
.AddFluentValidation(cfg =>
69+
{
70+
// Configure SlimMessageBus.Host.FluentValidation plugin
71+
cfg.AddProducerValidatorsFromAssemblyContaining<CreateCustomerCommandValidator>();
72+
73+
// You can map the validation errors into a custom exception
74+
//cfg.AddValidationErrorsHandler(errors => new ApplicationException("Custom Validation Exception"));
75+
}));
7476

75-
// Register FluentValidation validators
77+
// FluentValidation library - find and register IValidator<T> implementations:
7678
builder.Services.AddValidatorsFromAssemblyContaining<CreateCustomerCommandValidator>();
7779
```
7880

7981
#### Custom exception
8082

8183
By default `FluentValidation.ValidationException` exception is raised on the producer and consumer when validation fails.
82-
It is possible to configure custom exception (or perhaps to supress the validation errors):
84+
It is possible to configure custom exception (or perhaps to suppress the validation errors):
8385

8486
```cs
8587
builder.Services.AddSlimMessageBus(mbb =>
@@ -149,4 +151,4 @@ If you are using another DI container than Microsoft.Extensions.DependencyInject
149151
- register the FluentValidator `IValidator<T>` validators in the container,
150152
- register the respective `ProducerValidationInterceptor<T>` as `IProducerInterceptor<T>` for each of the message type `T` that needs to be validated on producer side,
151153
- register the respective `ConsumerValidationInterceptor<T>` as `IConsumerInterceptor<T>` for each of the message type `T` that needs to be validated on consumer side,
152-
- the scope of can be anything that you need (scoped, transient, singleton)
154+
- the scope of can be anything that you need (scoped, transient, singleton)

docs/plugin_fluent_validation.t.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# FluentValidation Plugin for SlimMessageBus <!-- omit in toc -->
2+
3+
Please read the [Introduction](intro.md) before reading this provider documentation.
4+
5+
- [Introduction](#introduction)
6+
- [Configuration](#configuration)
7+
- [Configuring FluentValidation](#configuring-fluentvalidation)
8+
- [Custom exception](#custom-exception)
9+
- [Producer side validation](#producer-side-validation)
10+
- [Consumer side validation](#consumer-side-validation)
11+
- [Configuring without MSDI](#configuring-without-msdi)
12+
13+
## Introduction
14+
15+
The [`SlimMessageBus.Host.FluentValidation`](https://www.nuget.org/packages/SlimMessageBus.Host.FluentValidation) introduces validation on the producer or consumer side by leveraging the [FluentValidation](https://www.nuget.org/packages/FluentValidation) library.
16+
The plugin is based on [`SlimMessageBus.Host.Interceptor`](https://www.nuget.org/packages/SlimMessageBus.Host.Interceptor) core interfaces and can work with any transport including the memory bus.
17+
18+
See the [full sample](/src/Samples/Sample.ValidatingWebApi/).
19+
20+
## Configuration
21+
22+
Consider the following command, with the validator (using FluentValidation) and command handler:
23+
24+
@[:cs](../src/Samples/Sample.ValidatingWebApi/Commands/CreateCustomerCommand.cs,Example)
25+
26+
@[:cs](../src/Samples/Sample.ValidatingWebApi/Commands/CreateCustomerCommandValidator.cs,Example)
27+
28+
@[:cs](../src/Samples/Sample.ValidatingWebApi/Commands/CreateCustomerCommandHandler.cs,Example)
29+
30+
### Configuring FluentValidation
31+
32+
Consider an in-process command that is delivered using the memory bus:
33+
34+
@[:cs](../src/Samples/Sample.ValidatingWebApi/Program.cs,Configuration)
35+
36+
#### Custom exception
37+
38+
By default `FluentValidation.ValidationException` exception is raised on the producer and consumer when validation fails.
39+
It is possible to configure custom exception (or perhaps to suppress the validation errors):
40+
41+
```cs
42+
builder.Services.AddSlimMessageBus(mbb =>
43+
{
44+
mbb.AddFluentValidation(opts =>
45+
{
46+
// SMB FluentValidation setup goes here
47+
opts.AddValidationErrorsHandler(errors => new ApplicationException("Custom exception"));
48+
});
49+
});
50+
```
51+
52+
#### Producer side validation
53+
54+
The `.AddProducerValidatorsFromAssemblyContaining()` will register an SMB interceptor that will validate the message upon `.Publish()` or `.Send()` - on the producer side before the message even gets deliverd to the underlying transport. Continuing on the example from previous section:
55+
56+
```cs
57+
builder.Services.AddSlimMessageBus(mbb =>
58+
{
59+
mbb.AddFluentValidation(opts =>
60+
{
61+
// Register validation interceptors for message (here command) producers inside message bus
62+
// Required Package: SlimMessageBus.Host.FluentValidation
63+
opts.AddProducerValidatorsFromAssemblyContaining<CreateCustomerCommandValidator>();
64+
});
65+
});
66+
```
67+
68+
For example given an ASP.NET Minimal WebApi, the request can be delegated to SlimMessageBus in memory transport:
69+
70+
```cs
71+
// Using minimal APIs
72+
var app = builder.Build();
73+
74+
app.MapPost("/customer", (CreateCustomerCommand command, IMessageBus bus) => bus.Send(command));
75+
76+
await app.RunAsync();
77+
```
78+
79+
In the situation that the incoming HTTP request where to deliver an invalid command, the request will fail with `FluentValidation.ValidationException: Validation failed` exception.
80+
81+
For full example, please see the [Sample.ValidatingWebApi](../src/Samples/Sample.ValidatingWebApi/) sample.
82+
83+
#### Consumer side validation
84+
85+
We can also enable validation of the incoming message just before it gets delivered to the respective `IConsumer<T>` or `IRequestHandler<T, R>` - on the consumer side.
86+
Such validation would be needed in scenarios when an external system delivers messages onto the transport (Kafka, Azure Service Bus) which we do not trust, and therefore we could enable validation on the consumer end. This will prevent the invalid messages to enter the consumer or handler.
87+
88+
```cs
89+
builder.Services.AddSlimMessageBus(mbb =>
90+
{
91+
mbb.AddFluentValidation(opts =>
92+
{
93+
// Register validation interceptors for message (here command) consumers inside message bus
94+
// Required Package: SlimMessageBus.Host.FluentValidation
95+
opts.AddConsumerValidatorsFromAssemblyContaining<CreateCustomerCommandValidator>();
96+
});
97+
});
98+
```
99+
100+
In the situation that the message is invalid, the message will fail with `FluentValidation.ValidationException: Validation failed` exception and standard consumer error handling will take place (depending on the underlying transport it might get retried multiple times until it ends up on dead-letter queue).
101+
102+
### Configuring without MSDI
103+
104+
If you are using another DI container than Microsoft.Extensions.DependencyInjection, in order for the `SlimMessageBus.Host.FluentValidation` plugin to work, you simply need to:
105+
106+
- register the FluentValidator `IValidator<T>` validators in the container,
107+
- register the respective `ProducerValidationInterceptor<T>` as `IProducerInterceptor<T>` for each of the message type `T` that needs to be validated on producer side,
108+
- register the respective `ConsumerValidationInterceptor<T>` as `IConsumerInterceptor<T>` for each of the message type `T` that needs to be validated on consumer side,
109+
- the scope of can be anything that you need (scoped, transient, singleton)

0 commit comments

Comments
 (0)