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?