MVFC.Messaging.InMemory
2.0.3
See the version list below for details.
dotnet add package MVFC.Messaging.InMemory --version 2.0.3
NuGet\Install-Package MVFC.Messaging.InMemory -Version 2.0.3
<PackageReference Include="MVFC.Messaging.InMemory" Version="2.0.3" />
<PackageVersion Include="MVFC.Messaging.InMemory" Version="2.0.3" />
<PackageReference Include="MVFC.Messaging.InMemory" />
paket add MVFC.Messaging.InMemory --version 2.0.3
#r "nuget: MVFC.Messaging.InMemory, 2.0.3"
#:package MVFC.Messaging.InMemory@2.0.3
#addin nuget:?package=MVFC.Messaging.InMemory&version=2.0.3
#tool nuget:?package=MVFC.Messaging.InMemory&version=2.0.3
MVFC.Messaging.InMemory
🇧🇷 Leia em Português
A .NET messaging provider for in-memory messaging, built on top of MVFC.Messaging.Core. Provides InMemoryPublisher<T> and InMemoryConsumer<T> backed by System.Threading.Channels.Channel<T> — ideal for unit testing, integration testing, and local development without external infrastructure.
Package
| Package | Downloads |
|---|---|
| MVFC.Messaging.InMemory |
Installation
dotnet add package MVFC.Messaging.InMemory
This package depends on MVFC.Messaging.Core (installed automatically). No external dependencies.
Configuration
The InMemory provider requires no external infrastructure — no connection strings, no credentials, no brokers. Both the publisher and consumer share a Channel<T> instance that acts as the in-memory message queue:
using System.Threading.Channels;
// Unbounded channel — no backpressure, accepts messages indefinitely
var channel = Channel.CreateUnbounded<OrderCreated>();
// Bounded channel — limits the buffer to 100 messages (producer blocks when full)
var channel = Channel.CreateBounded<OrderCreated>(100);
The publisher and consumer must share the same Channel<T> instance for messages to flow between them.
Usage
Publishing a Single Message
using System.Threading.Channels;
using MVFC.Messaging.InMemory.Memory;
var channel = Channel.CreateUnbounded<OrderCreated>();
await using var publisher = new InMemoryPublisher<OrderCreated>(channel);
var order = new OrderCreated(1, "Keyboard", 149.90m);
await publisher.PublishAsync(order);
Messages are written directly to the channel — no serialization overhead.
Publishing a Batch
Batch publishing writes each message sequentially to the channel:
var orders = new[]
{
new OrderCreated(1, "Keyboard", 149.90m),
new OrderCreated(2, "Mouse", 59.90m),
new OrderCreated(3, "Monitor", 899.00m)
};
await publisher.PublishBatchAsync(orders);
Consuming Messages
The consumer reads from the channel using ReadAllAsync, which yields messages as they arrive:
using System.Threading.Channels;
using MVFC.Messaging.InMemory.Memory;
var channel = Channel.CreateUnbounded<OrderCreated>();
await using var consumer = new InMemoryConsumer<OrderCreated>(channel);
await consumer.StartAsync(async (message, ct) =>
{
Console.WriteLine($"Processing order #{message.OrderId}: {message.Product}");
// Your business logic here
}, cancellationToken);
// ... later, when shutting down:
await consumer.StopAsync();
Consumer behavior:
- Reads from the channel using
Channel.Reader.ReadAllAsync, which is a native async stream — no polling or delays. - Messages are passed directly to the handler (no deserialization needed).
StartAsynclaunches a backgroundTask.Runloop;StopAsynccancels it and waits for completion.
Complete Publish + Consume Example
using System.Threading.Channels;
using MVFC.Messaging.InMemory.Memory;
var channel = Channel.CreateUnbounded<OrderCreated>();
await using var publisher = new InMemoryPublisher<OrderCreated>(channel);
await using var consumer = new InMemoryConsumer<OrderCreated>(channel);
// Start consuming
var received = new TaskCompletionSource<OrderCreated>();
await consumer.StartAsync(async (msg, ct) =>
{
Console.WriteLine($"Received: Order #{msg.OrderId} — {msg.Product}");
received.SetResult(msg);
}, CancellationToken.None);
// Publish
await publisher.PublishAsync(new OrderCreated(42, "Keyboard", 149.90m));
// Wait for the message to be consumed
var result = await received.Task.WaitAsync(TimeSpan.FromSeconds(5));
// Cleanup
await consumer.StopAsync();
Using in Unit Tests
The InMemory provider is perfect for testing messaging logic without external dependencies:
[Fact]
public async Task Should_Process_Order_When_Published()
{
// Arrange
var channel = Channel.CreateUnbounded<OrderCreated>();
await using var publisher = new InMemoryPublisher<OrderCreated>(channel);
await using var consumer = new InMemoryConsumer<OrderCreated>(channel);
var tcs = new TaskCompletionSource<OrderCreated>();
await consumer.StartAsync(async (msg, ct) => tcs.SetResult(msg), CancellationToken.None);
// Act
var order = new OrderCreated(1, "Test Product", 9.99m);
await publisher.PublishAsync(order);
// Assert
var result = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5));
Assert.Equal(1, result.OrderId);
Assert.Equal("Test Product", result.Product);
await consumer.StopAsync();
}
API Reference
InMemoryPublisher<T>
| Constructor | Parameters |
|---|---|
InMemoryPublisher<T>(Channel<T> channel) |
The shared channel to write messages to |
| Method | Description |
|---|---|
PublishAsync(T message, CancellationToken ct) |
Writes the message directly to the channel |
PublishBatchAsync(IEnumerable<T> messages, CancellationToken ct) |
Writes each message sequentially to the channel |
DisposeAsync() |
No-op (channel is managed externally) |
InMemoryConsumer<T>
| Constructor | Parameters |
|---|---|
InMemoryConsumer<T>(Channel<T> channel) |
The shared channel to read messages from |
| Method | Description |
|---|---|
StartAsync(Func<T, CancellationToken, Task> handler, CancellationToken ct) |
Starts reading from the channel in a background task |
StopAsync(CancellationToken ct) |
Cancels the background task and waits for completion |
DisposeAsync() |
Cancels the background task and disposes the CancellationTokenSource |
Requirements
- .NET 9.0+
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- MVFC.Messaging.Core (>= 2.0.3)
-
net9.0
- MVFC.Messaging.Core (>= 2.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.