Search code examples
c#.net-coreasync-await

How to do async Windows Service ExecuteAsync properly?


This question is on strike....


Solution

  • You should avoid async void. async void is intended for event handlers; most other usages are misuses. async Task is the natural signature for an async method without a return value.

    So, change ListenForUdpMessages and ListenForHttpConnections to be async Task instead of async void.

    This then brings up the question: "what should I do with those tasks?". Your ExecuteAsync calls both those methods; it should do something with them. awaiting them one at a time is not a good idea, because you want them both running concurrently. The solution for asynchronous concurrency is to use Task.WhenAll, something like this:

    _logger.LogInformation("Worker running at: {RunningTime}", DateTimeOffset.Now);
    var udpTask = _hubService.ListenForUdpMessages();
    var httpTask = _managementService.ListenForHttpConnections();
    await Task.WhenAll(udpTask, httpTask);
    

    And now your exception handling in ExecuteAsync will work for exceptions propagated from those methods.

    Side notes:

    • "there is a management UI (hosting in the Windows Service)" - I hope you mean the management UI connects to the Win32 service, and that the Win32 service does not provide a UI directly. Win32 services providing UIs has been frowned upon for decades and I'm not sure if it's even possible with modern versions of Windows.
    • You have a "main loop with independent workers" kind of pattern going on in your HTTP listener. I strongly recommend self-hosting ASP.NET instead. If you really do need your own main loop with independent workers, then I recommend using something like my structured concurrency library to manage the workers rather than just throwing them on the thread pool.