0

Not 100% au fait with windows services, I have the following:

protected override void OnStart(string[] args)
{
    _myManager.Start();
}

In MyManager:

public void Start()
{
    _myTask = Task.Run(DoStuff);
}

In theory then, the OnStart method will return and the service will launch successfully. async Task DoStuff() is just an infinite loop (it will exit if the service is stopped though).

I want to add try/catch to this. Ideally it would be in the OnStart method, so that I can call this.Stop() to stop the service (since it will be the ServiceBase). This is to catch any exceptions I haven't explicitly handled, so I can log them and shut down the service.

Can I simply wrap a try catch around _myManager.Start();? Or do I need to do something clever involving tasks?

NibblyPig
  • 51,118
  • 72
  • 200
  • 356
  • 1
    `async void Start()`, then `try { await Task.Run(DoStuff); } catch { ... }` – canton7 Feb 10 '20 at 12:56
  • I had no idea `async void` was legal, I thought it had to be `async Task`! Interesting. I also have no idea what it does... – NibblyPig Feb 10 '20 at 12:58
  • 1
    Time to do some reading up on `async/await`! `async void` is discouraged, mostly for good reason, but it's a good fit for your question. – canton7 Feb 10 '20 at 13:00
  • The problem I have is understanding the flow of the program, if you await something then it'll wait until the task is done before executing the next line, but for some reason in a windows service, it will return the method and allow the service to start. This really boggles my mind. Can't I just put a try catch around `_myManager.Start()`? Probably not right, since that spawns a separate task. That's where it breaks down & I don't really know what to do. The async/await examples don't seem to talk about this, cos I've been using async/await for years in asp.net with no problems but this is new – NibblyPig Feb 10 '20 at 13:02
  • https://stackoverflow.com/questions/12980712/what-is-the-best-way-to-catch-exception-in-task This answer should give you a better understanding of your options to do so. – vsarunov Feb 10 '20 at 13:08
  • If I make my OnStart async, do I then make my `Start()` method return `Task.Run(DoStuff)`? Or do I keep it as it currently is? Or do I wrap it in a Task to return it? I could even do `await Task.Run`. But then perhaps I shouldn't await the `Start()` method if I do that to stop the service blocking? – NibblyPig Feb 10 '20 at 13:08
  • I think my confusion comes with exactly what happens when you start a task and don't await it. For example if you do it in a console application your console application will exit. But for some reason it's OK to do it in a windows service. – NibblyPig Feb 10 '20 at 13:14
  • 1
    When the Main method in a console application returns, the application is closed. When OnStart in a service returns, the service continues to run. This is down to how console apps / services were designed to work – canton7 Feb 10 '20 at 13:19
  • Makes sense, but what does 'returned' mean? Because you don't actually `return`. When you launch a windows service it seems to run OnStart, expecting it to spawn a thread and then 'exit' basically. I wouldn't have expected `await` to trigger that since it isn't exiting. But apparently it *is* exiting. But it will also un-exit and resume once the await is finished... – NibblyPig Feb 10 '20 at 13:26
  • @NibblyPig at some point, you `OnStart` method returns. When it's finished executing the last line of code in the method, the method returns. – canton7 Feb 10 '20 at 14:03
  • What confuses me is that OnStart needs to return, but if I do `await MyInfiniteTask()` that counts as returning. But what if after `MyInfiniteTask()` I do an unawaited simple `while (true){}`? Without the await, OnStart would never return and the service would not start. But with the await, even though there's still an infinite loop in OnStart, it would return. It boggles my mind. – NibblyPig Feb 10 '20 at 14:29
  • Right, an `async` method returns at the point that you hit the first `await`. I recommend reading up on how `async/await` works. It's not magic: there are some basic concepts from which everything else follows – canton7 Feb 10 '20 at 14:30

1 Answers1

1

You will want to use "ContinueWith", and define an error handler function which should probably log the error to the Windows Event Log, and stop the service.

You don't want to wait/block in OnStart() because Windows is expecting that to return quickly (and will report an error if it doesn't start in a timely manner).

See here for some more discussion: What is the best way to catch exception in Task?

  • 1
    Generally the less you use the `ContinueWith` and other similar legacy TPL APIs, the better. We are in the async/await era now! – Theodor Zoulias Feb 10 '20 at 15:07