We have Web API controllers that look like this:
public class HomeController : ApiController
{
Logger logger = new Logger();
[HttpGet, Route("")]
public IHttpActionResult Index()
{
logger.Info("Some info logging");
return Ok();
}
}
Internally, our loggers use the HttpClient
to POST
data to an Azure Event Hub. This means that the logger has a synchronous method which internally calls an asynchronous method.
The broken implementation
When our logger has a private method with an async void
signature like this:
public class Logger
{
public void Info(string message)
{
LogAsync(message);
}
private async void LogAsync(string message)
{
await PostAsync(message);
}
}
We see the following error:
The working implementation
If we change our logger to use an async Task
signature like this it works:
public class Logger
{
public void Info(string message)
{
LogAsync(message);
}
private async Task LogAsync(string message)
{
await PostAsync(message);
}
}
The question
In both cases our logging messages are sent to the Event Hub. I'd like to know why async Task
allows the controller to return the expected result, and async void
results in an InvalidOperationException
?
Also, is there any best practice regarding calling into asynchronous code from a synchronous method?
I've posted a sample solution here: https://github.com/kevinkuszyk/async-task-vs-async-void-sample