I have a C# (4.8) windows service. All it does is OnStart it registers some event handlers which gets called by a messagequeue when a message arrives and the event handler to process it. The event handler calls a library method to process it. This is all synchronous. Now as part of making everything async await pattern, all the processing logic in the library is now rewritten to be async await. Now the problem is the event handlers in windows service. I get error when I make them async void saying it needs to be a task. I know in UI application we can make async void. Is it not allowed in windows services? Also say I make it async void, then I have the problem of handling exception as they won't be caught there since there is no task. I also need to consider if there are any implications w.r.t SynchronizationContext as Win Services have the default context anyway and event handlers capture the context when async.
-
3*"I get error when I make them async void saying it needs to be a task."* - The compiler won't give you any such error. Can you show your code? The whole reason `async void` is even allowed is for event handlers. – Gabriel Luci Jun 26 '20 at 15:11
-
It was a warning not error. Sorry about that. The point was I dont want to use async void as it is not a UI related event handler but a library based event handler. Not sure if that makes a difference though – Krishnan Jul 01 '20 at 01:15
2 Answers
If you want to use C# event handlers, then you're stuck with void
. There's no way around that. And if you want use async
code in an event handler, then you're stuck with async void
.
That's not necessarily bad here. Events are really just a notification of "hey this happened" and go on your way. It's not the job of the code that raised the event to be concerned about what the event handler does or when or if it completes successfully. It did it's job of saying "hey this happened".
Most of the time anyway.... That separation of concerns can get blurred sometimes. For example, take the Form.Closing
event in WebForms. That is a notification that the window is about to close. After the event handler returns, the window closes. But await
works by returning and completing the rest of the work later. That means that an asynchronous Closing
event handler won't finish completely before the window closes, which of course causes problems.
So if:
- Your code does not depend on the event handler completing successfully before doing other work,
- Your code will not be handling or caring about exceptions in the event handler code, or
- You want to allow more than one event handler to subscribe
Then just use normal event handlers.
Another way is to accept an asynchronous delegate as a parameter to one of your initialization methods (or even a property if you wanted). For example, consider this class:
public class Test {
private readonly Func<Task> _somethingHappenedHandler;
public Test(Func<Task> somethingHappenedHandler) {
_somethingHappenedHandler = somethingHappenedHandler;
}
public async Task DoSomething() {
//do something
await _somethingHappenedHandler();
}
}
Which you could use like this:
public async Task SomethingHappened() {
await Task.Delay(1000);
Console.WriteLine("Something happened");
}
var test = new Test(SomethingHappened);
await test.DoSomething();
You can use this method if you need to know that the event handler completed successfully before continuing. But you lose the ability of subscribing multiple event handlers, but that may not be something you care about.
You should also think about how you will handle exceptions that happen in the handler. Will you ignore them and put that burden on the event handler code? Or handle them somehow?

- 38,328
- 4
- 55
- 84
You can do async void
however it will be executed as fire-and-forget event - the event sender can't await it, hence it can't know when you finished the event handling. If you are fine with this behavior in your use case, just add try catch in the handler (as you have said, it's not possible to handle errors thrown by async void
method. If you have to finish the handling before returning control to sender - use Wait()
on your async handler. As far as I know Windows Service doesn't have Sync Context and you won't get deadlock here.

- 4,595
- 25
- 38
-
The issue is I don't want to use Wait/Result and also possibly I am looking for a custom event which returns a Task so that I could properly use await in the event handler. Just need to figure how the event firing will happen especially those exposed by third party libraries. I am thinking maybe I could capture the actual event exposed by MSMQ and then fire my custom event from the handler but at that point it becomes again sync to async call. – Krishnan Jul 01 '20 at 01:14
-
@Krishnan you have to decide if you can handle the event in fire-and-forget manner or not. If not, you don't have another choice except `Wait`'ing the async handler. – Artur Jul 01 '20 at 05:58