MVFC.Messaging.InMemory 2.0.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package MVFC.Messaging.InMemory --version 2.0.2
                    
NuGet\Install-Package MVFC.Messaging.InMemory -Version 2.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MVFC.Messaging.InMemory" Version="2.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MVFC.Messaging.InMemory" Version="2.0.2" />
                    
Directory.Packages.props
<PackageReference Include="MVFC.Messaging.InMemory" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MVFC.Messaging.InMemory --version 2.0.2
                    
#r "nuget: MVFC.Messaging.InMemory, 2.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MVFC.Messaging.InMemory@2.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MVFC.Messaging.InMemory&version=2.0.2
                    
Install as a Cake Addin
#tool nuget:?package=MVFC.Messaging.InMemory&version=2.0.2
                    
Install as a Cake Tool

MVFC.Messaging.InMemory

🇧🇷 Leia em Português

CI codecov License Platform NuGet Version NuGet Downloads

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 Downloads

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).
  • StartAsync launches a background Task.Run loop; StopAsync cancels 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

Apache-2.0

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.0.2 118 4/5/2026
3.0.1 106 4/3/2026
2.0.4 112 3/21/2026
2.0.3 97 3/21/2026
2.0.2 105 3/21/2026
2.0.1 104 3/19/2026
1.0.2 242 12/19/2025
1.0.1 268 12/19/2025
1.0.0 262 12/19/2025