StreamWriter uses synchronous invocation when calling asynchronous methods

.net, async-await, streamwriter

Solution

I spotted the source of confusion.

`StreamWriter` flushes synchronously by default unless you specifically flush asynchronously.

`Stream.Flush` is called when closing, and of course, flushing.

This will invoke `Write` rather than `WriteAsync` in the `messageWriter` stream:

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
    await sw.WriteAsync("Hi");

The `StreamWriter` will buffer the "Hi" message, and it will be released to the underlying stream on the `Flush` invocation synchronously when closing the `StreamWriter`.

So the asynchronous call to `StreamWriter.WriteAsync` could have no effect on the underlying stream (because the buffering), and when calling `StreamWriter.Close`, `StreamWriter.Flush` is called synchronously, and therefore the `Flush` method on the underlying stream.

This code also calls `Write` synchronously:

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
{
    sw.AutoFlush = true; // will call Write here to send the UTF8 BOM
    await sw.WriteAsync("Hi"); // Write the actual data 
}

obviously also this this:

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
{
    await sw.WriteAsync("Hi"); 
    sw.Flush(); 
}

This will call `WriteAsync`:

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
{
    await sw.WriteAsync("Hi");
    await sw.FlushAsync()
}

I have created a simple class to track how the methods are called:

public class MSWrite : MemoryStream
{
    public override bool CanWrite { get { return true; } }

    public override void Write(byte[] buffer, int offset, int count)
    {
        Console.WriteLine("Write");
    }

    public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
    {
        Console.WriteLine("WriteAsync");
        return Task.Run(() => { });
    }
}

And this test:

Console.WriteLine("Simple");
using(var ms = new MSWrite())
using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
{
    await sw.WriteAsync("Hi");
}
Console.WriteLine();

Console.WriteLine("AutoFlush");
using (var ms = new MSWrite())
using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
{
    sw.AutoFlush = true;
    await sw.WriteAsync("Hi");
}
Console.WriteLine();

Console.WriteLine("Flush async");
using (var ms = new MSWrite())
using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
{
    await sw.WriteAsync("Hi");
    await sw.FlushAsync();
}

Yields:

Simple
Write
Write

AutoFlush
Write
WriteAsync

Flush async
WriteAsync
WriteAsync

The first write is the UTF8 BOM, the second is the actual data.

Problem

I am creating a stream like class, that inherits from `Stream`. When I use a `StreamWriter` class to write the information asynchronously: ``` using (var sw = new StreamWriter(messageWriter, Encoding.UTF8)) await sw.WriteAsync(msg); ``` I can see how `StreamWriter` goes straight to `void Stream.Write(byte[] buffer, int offset, int count)` rather than `Task Stream.WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)`. Is this a bug or am I missing something?

Original source