Skip to content

Commit 79855b0

Browse files
committed
[Host.Memory] mbb.AutoDeclareFrom() to use message type FullName by default
Signed-off-by: Tomasz Maruszak <[email protected]>
1 parent 975aa6d commit 79855b0

File tree

5 files changed

+145
-97
lines changed

5 files changed

+145
-97
lines changed

docs/provider_memory.md

+61-37
Original file line numberDiff line numberDiff line change
@@ -19,91 +19,115 @@ Please read the [Introduction](intro.md) before reading this provider documentat
1919

2020
## Introduction
2121

22-
The Memory transport provider can be used for internal communication within the same process. It is the simplest transport provider and does not require any external messaging infrastructure.
22+
The **Memory transport provider** enables message-based communication within a single process. It’s the simplest transport option in SlimMessageBus and doesn’t require any external infrastructure like Kafka or Azure Service Bus.
2323

24-
> Since messages are passed in memory and never persisted, they will be lost if the application process terminates while consuming these messages.
24+
> ⚠️ Messages are passed entirely in memory and are never persisted. If the application process terminates while messages are in-flight, those messages will be lost.
2525
26-
Good use case for in memory communication is:
26+
**Common use cases for in-memory transport include:**
2727

28-
- to integrate the domain layer with other application layers via domain events pattern,
29-
- to implement mediator pattern (when combined with [interceptors](intro.md#interceptors)),
30-
- to run unit tests against application code that normally runs with an out of process transport provider (Kafka, Azure Service Bus, etc),
31-
- to start simple messaging without having to provision messaging infrastructure, but when time comes reconfigure SMB to leverage messaging infrastructure.
28+
- Integrating the domain layer with other application layers using the **domain events** pattern.
29+
- Implementing the **mediator pattern** (especially when combined with [interceptors](intro.md#interceptors)).
30+
- Writing **unit tests** for messaging logic without requiring a full transport setup.
31+
- Starting with messaging quickly and easily — no infrastructure required — and switching to an external provider later by reconfiguring SlimMessageBus.
32+
33+
---
3234

3335
## Configuration
3436

35-
The memory transport is configured using the `.WithProviderMemory()`:
37+
First, install the NuGet package:
3638

37-
```cs
39+
```bash
40+
dotnet add package SlimMessageBus.Host.Memory
41+
```
42+
43+
Then, configure the memory transport using `.WithProviderMemory()`:
44+
45+
```csharp
3846
using SlimMessageBus.Host.Memory;
3947

4048
services.AddSlimMessageBus(mbb =>
4149
{
42-
// Bus configuration happens here (...)
43-
mbb.WithProviderMemory(); // requires SlimMessageBus.Host.Memory package
50+
// Configure your bus here...
51+
mbb.WithProviderMemory(); // Requires SlimMessageBus.Host.Memory package
4452
});
4553
```
4654

55+
> 💡 No serializer is needed by default for the in-memory transport — unless you [opt in to serialization](#serialization).
56+
4757
### Virtual Topics
4858

49-
Unlike other transport providers, memory transport does not have true notion of topics (or queues). However, it is still required to use topic names. This is required, so that the bus knows on which virtual topic to deliver the message to, and from what virtual topic to consume from.
59+
The in-memory transport doesn't use real topics or queues like other transport providers. However, **virtual topic names** are still required. These names allow the bus to correctly route messages to and from the appropriate consumers.
5060

51-
The consumer configuration side should use `.Topic()` to set the virtual topic name:
61+
On the **consumer side**, use `.Topic()` to specify the virtual topic:
5262

53-
```cs
54-
// declare that OrderSubmittedEvent will be consumed
63+
```csharp
64+
// Register a consumer for OrderSubmittedEvent
5565
mbb.Consume<OrderSubmittedEvent>(x => x.Topic(x.MessageType.Name).WithConsumer<OrderSubmittedHandler>());
5666

57-
// alternatively
67+
// Or use a hardcoded topic name
5868
mbb.Consume<OrderSubmittedEvent>(x => x.Topic("OrderSubmittedEvent").WithConsumer<OrderSubmittedHandler>());
5969
```
6070

61-
The producer configuration side should use `.DefaultTopic()` to set the virtual topic name:
71+
On the **producer side**, use `.DefaultTopic()` to define where messages should be published:
6272

63-
```cs
73+
```csharp
6474
mbb.Produce<OrderSubmittedEvent>(x => x.DefaultTopic("OrderSubmittedEvent"));
6575
```
6676

67-
> The virtual topic name can be any string. It helps to connect the relevant producers and consumers together.
77+
> Virtual topic names can be any string, as long as producers and consumers use the same value. This is what links them together internally.
6878
6979
### Auto Declaration
7080

71-
For bus configuration, we can leverage `.AutoDeclareFrom()` method to discover all the consumers (`IConsumer<T>`) and handlers (`IRequestHandler<T,R>`) types in an assembly and auto declare the respective producers and consumers/handlers in the bus.
72-
This can be useful to auto declare all of the domain event handlers in an application layer.
81+
You can simplify your bus configuration using the `.AutoDeclareFrom()` method, which scans an assembly to automatically discover all consumers (`IConsumer<T>`) and handlers (`IRequestHandler<T,R>`). It then declares the corresponding producers and consumers/handlers on the bus for you.
82+
This is especially useful for automatically registering all domain event handlers within an application layer.
7383

74-
```cs
84+
Example usage:
85+
86+
```csharp
7587
mbb
7688
.WithProviderMemory()
7789
.AutoDeclareFrom(Assembly.GetExecutingAssembly());
78-
// Alternatively specify the type of which assembly should be scanned
79-
// .AutoDeclareFromAssemblyContaining<CustomerCreateHandler>();
8090

81-
// If we want to filter to specific consumer/handler types then we can supply an additional filter:
82-
// .AutoDeclareFrom(Assembly.GetExecutingAssembly(), consumerTypeFilter: (consumerType) => consumerType.Name.EndsWith("Handler"));
83-
// .AutoDeclareFromAssemblyContaining<CustomerCreateHandler>(Assembly.GetExecutingAssembly(), consumerTypeFilter: (consumerType) => consumerType.Name.EndsWith("Handler"));
91+
// Alternatively, specify a type from the assembly you want to scan:
92+
// .AutoDeclareFromAssemblyContaining<CustomerCreateHandler>();
93+
94+
// You can also filter which consumers/handlers are picked up:
95+
// .AutoDeclareFrom(Assembly.GetExecutingAssembly(), consumerTypeFilter: consumerType => consumerType.Name.EndsWith("Handler"));
96+
// .AutoDeclareFromAssemblyContaining<CustomerCreateHandler>(consumerTypeFilter: consumerType => consumerType.Name.EndsWith("Handler"));
8497
```
8598

86-
For example, assuming this is the discovered handler type:
99+
For example, given a handler like this:
87100

88-
```cs
101+
```csharp
89102
public class EchoRequestHandler : IRequestHandler<EchoRequest, EchoResponse>
90103
{
91-
public Task<EchoResponse> OnHandle(EchoRequest request, CancellationToken cancellationToken) { /* ... */ }
104+
public Task<EchoResponse> OnHandle(EchoRequest request, CancellationToken cancellationToken)
105+
{
106+
// ...
107+
}
92108
}
93109
```
94110

95-
The bus auto registrations will set-up the producer and handler to the equivalent:
111+
The bus will automatically configure registrations equivalent to:
96112

97-
```cs
98-
mbb.Produce<EchoRequest>(x => x.DefaultTopic(x.MessageType.Name));
99-
mbb.Handle<EchoRequest, EchoResponse>(x => x.Topic(x.MessageType.Name).WithConsumer<EchoRequestHandler>());
113+
```csharp
114+
mbb.Produce<EchoRequest>(x => x.DefaultTopic(x.MessageType.FullName));
115+
mbb.Handle<EchoRequest, EchoResponse>(x => x.Topic(x.MessageType.FullName).WithConsumer<EchoRequestHandler>());
100116
```
101117

102-
The virtual topic name will be derived from the message type name by default. This can be customized by passing an additional parameter to the `AutoDeclareFrom()` method.
118+
By default, the virtual topic name is derived from the message type’s [`FullName`](https://learn.microsoft.com/en-us/dotnet/api/system.type.fullname?view=net-9.0) — meaning it includes both the namespace and any outer class names.
119+
You can customize this by providing your own `messageTypeToTopicConverter`:
120+
121+
```csharp
122+
services.AddSlimMessageBus(builder =>
123+
builder.WithProviderMemory()
124+
.AutoDeclareFrom(Assembly.GetExecutingAssembly(), messageTypeToTopicConverter: messageType => messageType.FullName)
125+
);
126+
```
103127

104-
Using `.AutoDeclareFrom()` to configure the memory bus is recommended, as it will declare the producers and consumers automatically as consumer types are added over time.
128+
Using `.AutoDeclareFrom()` is highly recommended when configuring the memory bus, as it ensures producers and consumers are kept up to date automatically as your application evolves.
105129

106-
> The `.AutoDeclareFrom()` and `.AutoDeclareFromAssembly<T>()` will also register the found consumers/handlers into MSDI (see [here](intro.md#autoregistration-of-consumers-interceptors-and-configurators)).
130+
> Note: `.AutoDeclareFrom()` and `.AutoDeclareFromAssemblyContaining<T>()` will also register discovered consumers and handlers into the Microsoft Dependency Injection (MSDI) container. [Learn more here](intro.md#autoregistration-of-consumers-interceptors-and-configurators).
107131
108132
#### Polymorphic message support
109133

docs/provider_memory.t.md

+61-37
Original file line numberDiff line numberDiff line change
@@ -19,91 +19,115 @@ Please read the [Introduction](intro.md) before reading this provider documentat
1919

2020
## Introduction
2121

22-
The Memory transport provider can be used for internal communication within the same process. It is the simplest transport provider and does not require any external messaging infrastructure.
22+
The **Memory transport provider** enables message-based communication within a single process. It’s the simplest transport option in SlimMessageBus and doesn’t require any external infrastructure like Kafka or Azure Service Bus.
2323

24-
> Since messages are passed in memory and never persisted, they will be lost if the application process terminates while consuming these messages.
24+
> ⚠️ Messages are passed entirely in memory and are never persisted. If the application process terminates while messages are in-flight, those messages will be lost.
2525
26-
Good use case for in memory communication is:
26+
**Common use cases for in-memory transport include:**
2727

28-
- to integrate the domain layer with other application layers via domain events pattern,
29-
- to implement mediator pattern (when combined with [interceptors](intro.md#interceptors)),
30-
- to run unit tests against application code that normally runs with an out of process transport provider (Kafka, Azure Service Bus, etc),
31-
- to start simple messaging without having to provision messaging infrastructure, but when time comes reconfigure SMB to leverage messaging infrastructure.
28+
- Integrating the domain layer with other application layers using the **domain events** pattern.
29+
- Implementing the **mediator pattern** (especially when combined with [interceptors](intro.md#interceptors)).
30+
- Writing **unit tests** for messaging logic without requiring a full transport setup.
31+
- Starting with messaging quickly and easily — no infrastructure required — and switching to an external provider later by reconfiguring SlimMessageBus.
32+
33+
---
3234

3335
## Configuration
3436

35-
The memory transport is configured using the `.WithProviderMemory()`:
37+
First, install the NuGet package:
3638

37-
```cs
39+
```bash
40+
dotnet add package SlimMessageBus.Host.Memory
41+
```
42+
43+
Then, configure the memory transport using `.WithProviderMemory()`:
44+
45+
```csharp
3846
using SlimMessageBus.Host.Memory;
3947

4048
services.AddSlimMessageBus(mbb =>
4149
{
42-
// Bus configuration happens here (...)
43-
mbb.WithProviderMemory(); // requires SlimMessageBus.Host.Memory package
50+
// Configure your bus here...
51+
mbb.WithProviderMemory(); // Requires SlimMessageBus.Host.Memory package
4452
});
4553
```
4654

55+
> 💡 No serializer is needed by default for the in-memory transport — unless you [opt in to serialization](#serialization).
56+
4757
### Virtual Topics
4858

49-
Unlike other transport providers, memory transport does not have true notion of topics (or queues). However, it is still required to use topic names. This is required, so that the bus knows on which virtual topic to deliver the message to, and from what virtual topic to consume from.
59+
The in-memory transport doesn't use real topics or queues like other transport providers. However, **virtual topic names** are still required. These names allow the bus to correctly route messages to and from the appropriate consumers.
5060

51-
The consumer configuration side should use `.Topic()` to set the virtual topic name:
61+
On the **consumer side**, use `.Topic()` to specify the virtual topic:
5262

53-
```cs
54-
// declare that OrderSubmittedEvent will be consumed
63+
```csharp
64+
// Register a consumer for OrderSubmittedEvent
5565
mbb.Consume<OrderSubmittedEvent>(x => x.Topic(x.MessageType.Name).WithConsumer<OrderSubmittedHandler>());
5666

57-
// alternatively
67+
// Or use a hardcoded topic name
5868
mbb.Consume<OrderSubmittedEvent>(x => x.Topic("OrderSubmittedEvent").WithConsumer<OrderSubmittedHandler>());
5969
```
6070

61-
The producer configuration side should use `.DefaultTopic()` to set the virtual topic name:
71+
On the **producer side**, use `.DefaultTopic()` to define where messages should be published:
6272

63-
```cs
73+
```csharp
6474
mbb.Produce<OrderSubmittedEvent>(x => x.DefaultTopic("OrderSubmittedEvent"));
6575
```
6676

67-
> The virtual topic name can be any string. It helps to connect the relevant producers and consumers together.
77+
> Virtual topic names can be any string, as long as producers and consumers use the same value. This is what links them together internally.
6878
6979
### Auto Declaration
7080

71-
For bus configuration, we can leverage `.AutoDeclareFrom()` method to discover all the consumers (`IConsumer<T>`) and handlers (`IRequestHandler<T,R>`) types in an assembly and auto declare the respective producers and consumers/handlers in the bus.
72-
This can be useful to auto declare all of the domain event handlers in an application layer.
81+
You can simplify your bus configuration using the `.AutoDeclareFrom()` method, which scans an assembly to automatically discover all consumers (`IConsumer<T>`) and handlers (`IRequestHandler<T,R>`). It then declares the corresponding producers and consumers/handlers on the bus for you.
82+
This is especially useful for automatically registering all domain event handlers within an application layer.
7383

74-
```cs
84+
Example usage:
85+
86+
```csharp
7587
mbb
7688
.WithProviderMemory()
7789
.AutoDeclareFrom(Assembly.GetExecutingAssembly());
78-
// Alternatively specify the type of which assembly should be scanned
79-
// .AutoDeclareFromAssemblyContaining<CustomerCreateHandler>();
8090

81-
// If we want to filter to specific consumer/handler types then we can supply an additional filter:
82-
// .AutoDeclareFrom(Assembly.GetExecutingAssembly(), consumerTypeFilter: (consumerType) => consumerType.Name.EndsWith("Handler"));
83-
// .AutoDeclareFromAssemblyContaining<CustomerCreateHandler>(Assembly.GetExecutingAssembly(), consumerTypeFilter: (consumerType) => consumerType.Name.EndsWith("Handler"));
91+
// Alternatively, specify a type from the assembly you want to scan:
92+
// .AutoDeclareFromAssemblyContaining<CustomerCreateHandler>();
93+
94+
// You can also filter which consumers/handlers are picked up:
95+
// .AutoDeclareFrom(Assembly.GetExecutingAssembly(), consumerTypeFilter: consumerType => consumerType.Name.EndsWith("Handler"));
96+
// .AutoDeclareFromAssemblyContaining<CustomerCreateHandler>(consumerTypeFilter: consumerType => consumerType.Name.EndsWith("Handler"));
8497
```
8598

86-
For example, assuming this is the discovered handler type:
99+
For example, given a handler like this:
87100

88-
```cs
101+
```csharp
89102
public class EchoRequestHandler : IRequestHandler<EchoRequest, EchoResponse>
90103
{
91-
public Task<EchoResponse> OnHandle(EchoRequest request, CancellationToken cancellationToken) { /* ... */ }
104+
public Task<EchoResponse> OnHandle(EchoRequest request, CancellationToken cancellationToken)
105+
{
106+
// ...
107+
}
92108
}
93109
```
94110

95-
The bus auto registrations will set-up the producer and handler to the equivalent:
111+
The bus will automatically configure registrations equivalent to:
96112

97-
```cs
98-
mbb.Produce<EchoRequest>(x => x.DefaultTopic(x.MessageType.Name));
99-
mbb.Handle<EchoRequest, EchoResponse>(x => x.Topic(x.MessageType.Name).WithConsumer<EchoRequestHandler>());
113+
```csharp
114+
mbb.Produce<EchoRequest>(x => x.DefaultTopic(x.MessageType.FullName));
115+
mbb.Handle<EchoRequest, EchoResponse>(x => x.Topic(x.MessageType.FullName).WithConsumer<EchoRequestHandler>());
100116
```
101117

102-
The virtual topic name will be derived from the message type name by default. This can be customized by passing an additional parameter to the `AutoDeclareFrom()` method.
118+
By default, the virtual topic name is derived from the message type’s [`FullName`](https://learn.microsoft.com/en-us/dotnet/api/system.type.fullname?view=net-9.0) — meaning it includes both the namespace and any outer class names.
119+
You can customize this by providing your own `messageTypeToTopicConverter`:
120+
121+
```csharp
122+
services.AddSlimMessageBus(builder =>
123+
builder.WithProviderMemory()
124+
.AutoDeclareFrom(Assembly.GetExecutingAssembly(), messageTypeToTopicConverter: messageType => messageType.FullName)
125+
);
126+
```
103127

104-
Using `.AutoDeclareFrom()` to configure the memory bus is recommended, as it will declare the producers and consumers automatically as consumer types are added over time.
128+
Using `.AutoDeclareFrom()` is highly recommended when configuring the memory bus, as it ensures producers and consumers are kept up to date automatically as your application evolves.
105129

106-
> The `.AutoDeclareFrom()` and `.AutoDeclareFromAssembly<T>()` will also register the found consumers/handlers into MSDI (see [here](intro.md#autoregistration-of-consumers-interceptors-and-configurators)).
130+
> Note: `.AutoDeclareFrom()` and `.AutoDeclareFromAssemblyContaining<T>()` will also register discovered consumers and handlers into the Microsoft Dependency Injection (MSDI) container. [Learn more here](intro.md#autoregistration-of-consumers-interceptors-and-configurators).
107131
108132
#### Polymorphic message support
109133

src/Host.Plugin.Properties.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<Import Project="Common.NuGet.Properties.xml" />
55

66
<PropertyGroup>
7-
<Version>3.2.0-rc102</Version>
7+
<Version>3.2.0-rc103</Version>
88
</PropertyGroup>
99

1010
</Project>

src/SlimMessageBus.Host.Memory/MemoryMessageBusBuilder.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ internal MemoryMessageBusBuilder(MessageBusBuilder other) : base(other)
1717
};
1818
}
1919

20-
private static string DefaultMessageTypeToTopicConverter(Type type) => type.Name;
20+
private static string DefaultMessageTypeToTopicConverter(Type type) => type.FullName;
2121

2222
private static ISet<Type> GetAncestorTypes(Type messageType)
2323
{

0 commit comments

Comments
 (0)