Skip to content
This repository was archived by the owner on Apr 29, 2022. It is now read-only.

Commit 0e08ede

Browse files
author
Anton Vorontsov
committed
Covered wildcard extensions in the documentation.
1 parent 18ba089 commit 0e08ede

File tree

2 files changed

+43
-23
lines changed

2 files changed

+43
-23
lines changed

docs/message-consumption.md

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
### Starting a consumer
44

5-
The first step that needs to be done to retrieve messages from queues is to start a consumer. This can be achieved by calling `StartConsuming` method of `IQueueService`.
6-
Without calling `StartConsuming` consumption exchanges will work only in production mode.
5+
The first step that has to be done to retrieve messages from queues is to start a consumer. This can be achieved by calling `StartConsuming` method of the `IQueueService`.
6+
Consumption exchanges will work only in message-production mode if `StartConsuming` method won't be called.
77

8-
Let's say that your configuration look like this.
8+
Let's say that your configuration looks like this.
99

1010
```c#
1111
public class Startup
@@ -27,13 +27,13 @@ public class Startup
2727
}
2828
```
2929

30-
You can register an `IHostedService` and inject the instance of `IQueueService` into it.
30+
You can register an `IHostedService` and inject the instance of the `IQueueService` into it.
3131

3232
```c#
3333
services.AddSingleton<IHostedService, ConsumingService>();
3434
```
3535

36-
And then simply call `StartConsuming` so consumer can work in a background.
36+
And then simply call `StartConsuming` so a consumer can work in the background.
3737

3838
```c#
3939
public class ConsumingService : IHostedService
@@ -64,7 +64,7 @@ public class ConsumingService : IHostedService
6464
}
6565
```
6666

67-
Otherwise you can implement a worker service template from .Net Core 3 like this.
67+
Otherwise, you can implement a worker service template from .Net Core 3 like this.
6868

6969
```c#
7070
public class Program
@@ -132,30 +132,40 @@ public class Startup
132132
}
133133
```
134134

135-
The RabbitMQ client configuration and exchange configuration sections not specified in this example, but covered [here](rabbit-configuration.md) and [here](exchange-configuration.md).
135+
RabbitMQ client and exchange configuration sections are not specified in this example, but covered [here](rabbit-configuration.md) and [here](exchange-configuration.md).
136136

137-
`IMessageHandler` implementation will "listen" for messages by specified routing key, or a collection of routing keys.
137+
`IMessageHandler` implementation will "listen" for messages by specified routing key, or a collection of routing keys. If it is necessary you can also register multiple message handler at once.
138138
```c#
139139
services.AddRabbitMqClient(clientConfiguration)
140140
.AddExchange("ExchangeName", isConsuming: true, exchangeConfiguration)
141-
.AddMessageHandlerSingleton<CustomMessageHandler>(new[] { "first.routing.key", "second.routing.key", "third.routing.key" });
141+
.AddMessageHandlerSingleton<CustomMessageHandler>("first.routing.key");
142+
.AddMessageHandlerSingleton<AnotherCustomMessageHandler>(new[] { "second.routing.key", "third.routing.key" });
142143
```
143144

144-
You can register it in two modes - **singleton** or **transient** using `AddMessageHandlerSingleton` or `AddMessageHandlerTransient` methods respectively.
145+
You can also use **pattern matching** in routes where `*` (star) can substitute for exactly one word and `#` (hash) can substitute for zero or more words.
145146

146147
```c#
147148
services.AddRabbitMqClient(clientConfiguration)
148149
.AddExchange("ExchangeName", isConsuming: true, exchangeConfiguration)
149-
.AddMessageHandlerTransient<CustomMessageHandler>(new[] { "first.routing.key", "second.routing.key", "third.routing.key" });
150+
.AddMessageHandlerSingleton<CustomMessageHandler>("*.routing.*");
151+
.AddMessageHandlerSingleton<AnotherCustomMessageHandler>(new[] { "#.key", "third.*" });
150152
```
151153

152-
If it is necessary you can also register multiple message handler at once.
154+
You are also allowed to specify the exact exchange which will be "listened" by message handler with the given routing key (or pattern).
153155

154156
```c#
155157
services.AddRabbitMqClient(clientConfiguration)
156158
.AddExchange("ExchangeName", isConsuming: true, exchangeConfiguration)
157-
.AddMessageHandlerTransient<CustomMessageHandler>("first.routing.key")
158-
.AddMessageHandlerTransient<AnotherCustomMessageHandler>("second.routing.key");
159+
.AddMessageHandlerSingleton<CustomMessageHandler>("*.*.*", "ExchangeName");
160+
.AddMessageHandlerSingleton<AnotherCustomMessageHandler>("routing.key", "ExchangeName");
161+
```
162+
163+
You can register it in two modes, **singleton** or **transient**, using `AddMessageHandlerSingleton` or `AddMessageHandlerTransient` methods respectively.
164+
165+
```c#
166+
services.AddRabbitMqClient(clientConfiguration)
167+
.AddExchange("ExchangeName", isConsuming: true, exchangeConfiguration)
168+
.AddMessageHandlerTransient<CustomMessageHandler>(new[] { "#.key", "third.*" });
159169
```
160170

161171
You can also set multiple message handlers for managing messages received by one routing key. This case can happen when you want to divide responsibilities between services (e.g. one contains business logic, and the other writes messages in the database).
@@ -200,8 +210,8 @@ public class CustomMessageHandler : IMessageHandler
200210
}
201211
```
202212

203-
The only exception is `IQueueService`, you can't inject it because of the appearance of cyclic dependencies. If you want to use an instance of `IQueueService` (e.g. handle one message and send another) use `INonCyclicMessageHandler`.
204-
`INonCyclicMessageHandler` can be registered the same way as `IMessageHandler`. There are similar semantic methods for adding it in **singleton** or **transient** mode.
213+
The only exception is `IQueueService`. You can't inject it inside a message handler because of the appearance of cyclic dependencies. If you want to use an instance of `IQueueService` (e.g. handle one message and send another) use `INonCyclicMessageHandler`.
214+
`INonCyclicMessageHandler` can be registered the same way as `IMessageHandler`. There are similar semantic methods for adding it in **singleton** or **transient** modes.
205215

206216
```c#
207217
services.AddRabbitMqClient(clientConfiguration)
@@ -232,8 +242,8 @@ public class CustomNonCyclicMessageHandler : INonCyclicMessageHandler
232242

233243
### Asynchronous message handlers
234244

235-
`IMessageHandler` and `INonCyclicMessageHandler` work synchronously, but if you want an async version then use `IAsyncMessageHandler` and `IAsyncNonCyclicMessageHandler`.
236-
There are extension methods that allows you to register it the same way as synchronous ones in **singleton** or **transient** modes.
245+
`IMessageHandler` and `INonCyclicMessageHandler` work synchronously, but if you want to use an async technology then use `IAsyncMessageHandler` and `IAsyncNonCyclicMessageHandler`.
246+
There are extension methods that allow you to register it the same way as synchronous ones in **singleton** or **transient** modes.
237247

238248
```c#
239249
services.AddRabbitMqClient(clientConfiguration)
@@ -288,11 +298,11 @@ So you can use async/await power inside your message handler.
288298

289299
The message handling process is organized as follows:
290300

291-
- `IQueueMessage` receives a message as a byte array and decodes it in UTF8 string.
292-
- `IQueueMessage` checks if there are any message handlers in collections of `IMessageHandler`, `IAsyncMessageHandler`, `INonCyclicMessageHandler` and `IAsyncNonCyclicMessageHandler` instances and forwards a message to them.
293-
- All subscribed message handlers (`IMessageHandler`, `IAsyncMessageHandler`, `INonCyclicMessageHandler`, `IAsyncNonCyclicMessageHandler`) process the message.
294-
- `IQueueMessage` acknowledges the message by its `DeliveryTag`.
295-
- If any exception occurs `IQueueMessage` acknowledges the message anyway and checks if the message has to be re-send. If exchange option `RequeueFailedMessages` is set `true` then `IQueueMessage` adds a header `"requeued"` to the message and sends it again with delay in 60 seconds. Mechanism of sending delayed messages covered in the message production [documentation](message-production.md).
301+
- `IQueueMessage` receives a message and delegates it to the `IMessageHandlingService`.
302+
- `IMessageHandlingService` gets a message (as a byte array) and decodes it to the UTF8 string. It also checks if there are any message handlers in collections of `IMessageHandler`, `IAsyncMessageHandler`, `INonCyclicMessageHandler` and `IAsyncNonCyclicMessageHandler` instances and forwards a message to them.
303+
- All subscribed message handlers (`IMessageHandler`, `IAsyncMessageHandler`, `INonCyclicMessageHandler`, `IAsyncNonCyclicMessageHandler`) process the given message.
304+
- `IMessageHandlingService` acknowledges the message by its `DeliveryTag`.
305+
- If any exception occurs `IMessageHandlingService` acknowledges the message anyway and checks if the message has to be re-send. If exchange option `RequeueFailedMessages` is set `true` then `IMessageHandlingService` adds a header `"requeued"` to the message and sends it again with delay in 60 seconds. Mechanism of sending delayed messages covered in the message production [documentation](message-production.md).
296306
- If any exception occurs within handling the message that has been already re-sent that message will not be re-send again (re-send happens only once).
297307

298308
For message production features see the [Previous page](message-production.md)

readme.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,16 @@ class Program
110110
You have to configure everything almost the same way as you have already done with producer. The main differences are that you need to declare (configure) consumption exchange calling `AddConsumptionExchange` instead of production exchange. For detailed information about difference in exchange declarations you may want to see the [documentation](./docs/exchange-configuration.md).
111111
The other important part is adding custom message handlers by implementing `IMessageHandler` interface and calling `AddMessageHandlerSingleton<T>` or `AddMessageHandlerTransient<T>` methods. `IMessageHandler` is a simple subscriber, which receives messages from a queue by selected routing key. You are allowed to set multiple message handlers for one routing key (e.g. one is writing it in a database, and the other does the business logic).
112112

113+
You can also use pattern matching while adding message handlers where `*` (star) can substitute for exactly one word and `#` (hash) can substitute for zero or more words.
114+
You are also allowed to specify the exact exchange which will be "listened" by the message handler with the given routing key (or a pattern).
115+
116+
```c#
117+
services.AddRabbitMqClient(rabbitMqSection)
118+
.AddConsumptionExchange("exchange.name", exchangeSection)
119+
.AddMessageHandlerSingleton<CustomMessageHandler>("*.*.key")
120+
.AddMessageHandlerSingleton<AnotherCustomMessageHandler>("#", "exchange.name");
121+
```
122+
113123
The very last step is to start "listening" (consuming) by simply calling `StartConsuming` method of `IQueueService`. After that you will start getting messages, and you can handle them in any way you want.
114124

115125
Message handler example.

0 commit comments

Comments
 (0)