ASP.NET – InvalidOperationException: Synchronous operations are disallowed

Problem

You’re trying to do synchronous IO operations in ASP.NET and you get the following exception:

System.InvalidOperationException: ‘Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true

The reason you’re getting this is because server option AllowSynchronousIO is false. Starting in ASP.NET Core 3.0, this is false by default.

Solution

Microsoft turned this setting off by default because doing sync IO is known to cause thread starvation and app hangs. You can either turn the setting back on, or use async instead.

Long-term solution – Refactor your code to be async all the way through

The long-term solution is to use async IO calls. Instead of WriteLine(), use WriteLineAsync().

In order to use async/await effectively, you need to use it throughout the entire call chain, starting from the API entry method.

As a simple example, here is an endpoint that sets up an SSE stream, and then uses WriteLine() to write a message to the subscriber. This results in the Synchronous operations are disallowed error.

[HttpGet]
[Route("messages/subscribe/{id}")]
public void Subscribe(string id)
{
	Response.ContentType = "text/event-stream";
	Response.StatusCode = 200;

	StreamWriter streamWriter = new StreamWriter(Response.Body);

	streamWriter.WriteLine($"{DateTime.Now} Hello subscriber");
	streamWriter.Flush();
}

Here’s how to refactor the code to be entirely async:

  • Change the Subscribe() method to use async Task.
  • Replace WriteLine() with WriteLineAsync() and await it.
  • Replace Flush() with FlushAsync() and await it.
[HttpGet]
[Route("messages/subscribe/{id}")]
public async Task Subscribe(string id)
{
	Response.ContentType = "text/event-stream";
	Response.StatusCode = 200;

	StreamWriter streamWriter = new StreamWriter(Response.Body);

	await streamWriter.WriteLineAsync($"{DateTime.Now} Hello subscriber");
	await streamWriter.FlushAsync();
}

Now when I call this endpoint it no longer throws the exception.

Short-term solution – Set AllowSynchronousIO=true

If you need a short-term solution to this problem, then you can turn the setting back on for your server.

You turn it on by enabling it in the server options in Startup.ConfigureServices for your specific server.

For example, the following sets AllowSynchronousIO=true for IIS:

public class Startup
{
	public void ConfigureServices(IServiceCollection services)
	{
		//other service methods
		
		services.Configure<IISServerOptions>(options =>
		{
			options.AllowSynchronousIO = true;
		});
	}
	
	//other methods in Startup
}

Leave a Comment