Skip to Content
Course content

55: IAsyncEnumerable and Async Streams

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, we've dealt with Task<List<T>> for asynchronous operations that return a collection. That works fine for a few dozen items, but imagine you're building a dashboard that streams thousands of log entries or a live news feed. If you use a List, the user has to wait for the entire collection to be fetched and loaded into memory before they see a single line of data. It's a terrible user experience.

That's where IAsyncEnumerable<T> comes in. It allows us to "stream" data. Instead of waiting for the whole bucket to fill up, we can hand over each item the moment it's ready. It's essentially the asynchronous version of yield return.

Simulating a Slow News API

Let's build a simple news aggregator. I want a method that simulates fetching articles from a remote server. Since network requests take time, I'll use Task.Delay to mimic that lag. Here is how I'll set up the provider:

public class NewsService
{
    private readonly string[] _mockArticles = 
    { 
        "C# 12 released!", 
        "Async streams are powerful", 
        "The rise of .NET 8", 
        "Understanding Memory<T>", 
        "Exploring Source Generators" 
    };

    public async IAsyncEnumerable<string> GetNewsFeedAsync()
    {
        foreach (var article in _mockArticles)
        {
            // Simulate network latency for each item
            await Task.Delay(500); 
            yield return article;
        }
    }
}

Notice the async IAsyncEnumerable<string> return type. This tells the compiler that this method is a state machine that will produce values over time, and that producing those values might involve awaiting other tasks.

The "foreach" trap

Now, here is where I usually trip up when I'm moving quickly. My muscle memory is so tuned to IEnumerable that I'll try to consume the stream like this:

var service = new NewsService();

// This will NOT compile!
foreach (var news in service.GetNewsFeedAsync())
{
    Console.WriteLine(news);
}

I get a compiler error immediately. Why? Because IAsyncEnumerable isn't a standard collection; it's a stream of tasks. A regular foreach loop doesn't know how to await the next item in the sequence. It's trying to iterate over the "stream" itself, not the values produced by the stream.

Streaming with await foreach

To fix this, we use await foreach. This tells C# to asynchronously wait for the next element to be yielded before executing the loop body. It keeps the thread free while the Task.Delay is happening in the background.

var service = new NewsService();

Console.WriteLine("Fetching news...");

await foreach (var news in service.GetNewsFeedAsync())
{
    Console.WriteLine($"Breaking News: {news}");
}

Console.WriteLine("Feed complete.");

If you run this, you'll see the articles pop up one by one every half-second. If we had used a Task<List<string>>, the console would have stayed blank for 2.5 seconds and then dumped all five lines at once. In a real-world UI, that's the difference between a "frozen" app and a responsive one.

One quick tip: if you're using IAsyncEnumerable in a project, make sure you have using System.Collections.Generic; at the top. It's where the interface lives. Also, remember that you can only use await foreach inside an async method.




📋 Practical Task

Build a Real-Time Log Streamer

Your task is to create a log simulation system that mimics reading a large log file from a disk or a remote server.

  • Create a class called LogReader.
  • Implement a method ReadLogsAsync() that returns an IAsyncEnumerable<string>.
  • Inside the method, use a loop to yield at least 10 mock log messages (e.g., "Log entry 1: System started", "Log entry 2: Connection established", etc.).
  • Introduce a random delay between 100ms and 1000ms for each log entry using Task.Delay() and a Random object to simulate unpredictable disk I/O.
  • In your Main method, consume this stream using await foreach and print each log to the console as it arrives.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.