Listen to this Post
Channels in .NET provide a powerful way to implement the producer-consumer pattern, enabling asynchronous communication between components. Below is a detailed guide on how to use Channels to create a simple in-memory message bus.
How to Use Channels in .NET
Channels consist of a `Writer` for publishing messages and a `Reader` for consuming them. Here’s a basic implementation:
using System.Threading.Channels;
// Create an unbounded channel (can also use bounded for limited capacity)
var channel = Channel.CreateUnbounded<string>();
// Producer: Write messages to the channel
async Task ProduceMessages()
{
for (int i = 0; i < 10; i++)
{
await channel.Writer.WriteAsync($"Message {i}");
Console.WriteLine($"Produced: Message {i}");
await Task.Delay(500);
}
channel.Writer.Complete(); // Signal no more messages
}
// Consumer: Read messages from the channel
async Task ConsumeMessages()
{
await foreach (var message in channel.Reader.ReadAllAsync())
{
Console.WriteLine($"Consumed: {message}");
}
}
// Run producer and consumer concurrently
var producer = ProduceMessages();
var consumer = ConsumeMessages();
await Task.WhenAll(producer, consumer);
You Should Know:
- Bounded vs. Unbounded Channels:
- Unbounded (
CreateUnbounded<T>()) allows unlimited messages. - Bounded (
CreateBounded<T>(capacity)) restricts queue size, useful for backpressure. -
Error Handling:
try { await channel.Writer.WriteAsync("Test"); } catch (ChannelClosedException) { Console.WriteLine("Channel closed!"); } -
Multiple Consumers:
var channel = Channel.CreateUnbounded<string>(); var consumer1 = ConsumeMessages("Consumer 1"); var consumer2 = ConsumeMessages("Consumer 2"); await Task.WhenAll(consumer1, consumer2); -
Performance Considerations:
- Channels are lock-free and optimized for high-throughput scenarios.
- For distributed systems, consider Azure Service Bus or RabbitMQ.
What Undercode Say:
Channels in .NET offer a lightweight alternative to MediatR for in-memory messaging, but they lack built-in retries, persistence, or distributed capabilities. For mission-critical systems, combine Channels with:
– Redis Pub/Sub (redis-cli SUBSCRIBE channel)
– Kafka (kafka-console-producer --topic test)
– Linux IPC (mkfifo /tmp/myfifo)
– Windows Named Pipes (New-Pipe -Name MyPipe)
For .NET developers, mastering Channels improves scalability, but always evaluate if an in-memory solution fits your reliability needs.
Expected Output:
A functional .NET Channel-based message queue with producer-consumer logging.
Reference:
References:
Reported By: Milan Jovanovic – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅



