Skip to main content

Command Palette

Search for a command to run...

Using Channels in an ASP.NET Core Real-World Application

Published
2 min read
Using Channels in an ASP.NET Core Real-World Application

Channels in C# provide a powerful and efficient way to manage asynchronous communication between producers and consumers, making them ideal for real-world ASP.NET Core applications that require background processing, task queues, or event streaming.

The Role of Channels in ASP.NET Core

In web applications, it’s common to have tasks that don’t need to be processed immediately or synchronously in the request pipeline—such as sending emails, processing files, or handling user notifications. Channels enable these tasks to be queued and processed by background services independently from the main application thread, improving responsiveness and scalability.

A Real-World Example: Background Task Queue with Channels

Imagine an online store where users add items to a cart. Rather than writing every cart update directly to the database synchronously (which could slow down user experience), you queue these updates into a channel. A background worker service then processes the queued operations in the background, ensuring database writes happen efficiently, and preventing the main application from becoming blocked.

Setting Up Channels in ASP.NET Core

You first create a bounded channel registered as a singleton service. The bounded nature protects the system by controlling the maximum queue size, which prevents memory overload during spikes.

csharp

builder.Services.AddSingleton(_ => Channel.CreateBounded<string>(new BoundedChannelOptions(100)

{

FullMode = BoundedChannelFullMode.Wait

}));

Background Service to Consume Channel Entries

A hosted background service reads messages or tasks from the channel and processes them asynchronously:

csharp

public class MessageProcessor : BackgroundService

{

private readonly Channel<string> _channel;

private readonly ILogger<MessageProcessor> _logger;

public MessageProcessor(Channel<string> channel, ILogger<MessageProcessor> logger)

{

_channel = channel;

_logger = logger;

}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)

{

_logger.LogInformation("Message processor starting");

await foreach (var message in _channel.Reader.ReadAllAsync(stoppingToken))

{

_logger.LogInformation("Processing message: {Message}", message);

// Simulate processing time

await Task.Delay(100, stoppingToken);

_logger.LogInformation("Message processed successfully: {Message}", message);

}

}

}

Enqueuing Work in API Controllers

When the application needs to queue a task, such as processing a new cart or sending a notification, it writes asynchronously to the channel:

csharp

await _channel.Writer.WriteAsync("Process cart update");

Benefits of Using Channels in ASP.NET Core

  • Efficient Asynchronous Processing: Decouple heavy or slow operations from HTTP request processing.

  • Backpressure Handling: Bounded channels prevent the app from running out of memory when workloads spike.

  • Scalability: Multiple consumers can be added to process tasks in parallel.

  • Graceful Shutdown: The channel and background service can signal completion and cleanly finish outstanding work.

Conclusion

Integrating channels in your ASP.NET Core applications provides a clean, scalable, and reliable approach to background processing and task queuing. Channels help keep your application responsive under load, simplify synchronization logic, and ensure critical background tasks are processed efficiently.

More from this blog

T

Tunde Hub

40 posts

Sharing practical insights, tools, and tutorials on .NET, ASP.NET Core, cloud, and open source, empowering developers to build with confidence and grow their craft.