5

I know this is a design question but I am trying to understand this to use it the best way. So consider this question as clarification of how it could be used with its most capabilities.

Why it is not designed KISS-based synchronized and have async methods (StartAsync, StopAsync), AFAIK, the main benefit of Async in web request is to let some idle threads be released to be used to serve further request but it can't be the case for IHostedService as there is no concept of request and there is always one running (or suspended) thread.

CodeFuller
  • 30,317
  • 3
  • 63
  • 79
mehran
  • 1,314
  • 4
  • 19
  • 33

1 Answers1

10

Let's go down the rabbit hole.

Instances of IHostedService are called by HostedServiceExecutor.StartAsync() which is asynchronous (HostedServiceExecutor source code).

HostedServiceExecutor.StartAsync() is called by WebHost.StartAsync() which is asynchronous (WebHost source code).

WebHost implements IWebHost which has both synchronous and asynchronous versions for start: Start and StartAsync. However WebHost.Start() implementation just calls asynchronous version:

public void Start()
{
    StartAsync().GetAwaiter().GetResult();
}

Finally WebHost.Start() is called by Program.Main (as generated by default ASP.NET Core project template):

public static void Main(string[] args)
{
    BuildWebHost(args).Run();
}

Having this calls chain, we could go on with your question "Why IHostedService is async?" and get "Why IWebHost is async?" or "Why c# 7 introduced async Main() method?".

You could get reasoning for this from the following discussions:

Well, the main reason is to simplify calls to async methods from program root. Usually the program flow requires calls to async methods (either your own implementation or 3rd party library). With old approach we were to do something like this:

public static void Main(string[] args)
{
    SomeAsyncCall().GetAwaiter().GetResult();
}

But now we could have it async all the way in a clean way:

static async Task Main(string[] args)
{
    await SomeAsyncCall();
}

The same applies for IHostedService.StartAsync(). It could require calling some async operations during the host service preparation. This discussion of host services concept has an explicit statement about this:

The StartAsync method is asynchronous because we may need to execute some preparation tasks for the job that may fail to execute and compromise the initialization.

Hope this answers your question.

If you are looking for docs about proper implementation of IHostedService, here is a good one: Implementing IHostedService in ASP.NET Core 2.0

CodeFuller
  • 30,317
  • 3
  • 63
  • 79
  • 1
    Nice one, thank you! Your explanation also makes it obvious why `BackgroundService.StartAsync` returns `Task.CompletedTask` if the `_executingTask` is running - because otherwise the start of the whole web app would be delayed – ironstone13 Feb 14 '19 at 19:50