You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
BackgroundService.StopAsync never completes when called from a WPF project from Application.Exit event or Application.OnExit override #42993
BackgroundService StopAsync never completes when called from a WPF project from Application.Exit event or Application.OnExit override. Not sure this is the right repo to open the issue so be patient with me.
I think a deadlock occurs but I've no idea how to prevent it. I've tried to debug the BackgroundService class and the offending part is the Task.WhenAny included in StopAsync. I've also tried to wrap the call to StopAsync in a Task but the effect is the same.
After calling Close() on the MainWindow my method Application_Exit is called, and I get this in my logs:
Information: Microsoft.Hosting.Lifetime[0]: Waiting for the host to be disposed. Ensure all 'IHost' instances are wrapped in 'using' blocks.
Maybe there is a "proper way" of using Microsoft.Extensions and IHost with WPF but I have no idea how to make them both work properly together.
When putting the _host in a using statement in all of the methods: the constructor App() , Application_Startup and Application_Exit, then the problem doesn't happen and the application closes properly, but of course, disposing the IHost right after constructing is definetely not the way to go haha.
Any insights on how to make Microsoft.Extensions and WPF work together nicely?
Yeah it's not a good solution, but can't really find any help with how to approach this situation. As for the exception, a good try/catch and that would do it haha.
I've tried to implement IHostLifetime but as the other solution, the IHostedService(s) are not shutdown gracefully. In fact, IHostLifetime.StopAsync is never called, as the IHostedService.StopAsync never completes.
EDIT: Updated sample project with all the relevant parts (IHostLifetime and IHostedService implementations)
privatevoidOnApplicationExit(objectsender,ExitEventArgse)// this method cannot be async, it MUST wait!{Task.Run(()=>_host.StopAsync()).Wait();_host.Dispose();_host=null;}
Or something like this:
privatevoidOnApplicationExit(objectsender,ExitEventArgse)// this method cannot be async, it MUST wait!{varframe=newDispatcherFrame(false);Task.Run(()=>{try{await_host.StopAsync();}finally{frame.Continue=false;}});Dispatcher.PushFrame(frame);_host.Dispose();_host=null;}
Test results, suggested solution 1:
Changed slightly adding async: Task.Run(async () => await _host.StopAsync()).Wait();
but this one ends with an AggregateException'Remove root: handle=10, parent=01s.WpfTap.Utility.)' containing a TaskCanceledException which (I think) referes to the actual task.
Test results, suggested solution 2:
Changed slightly adding async. This one appears to be working as expected! Thanks! Updated sample repo with this fix.
With #56057 we no longer block on ProcessExit in the ConsoleLifetime on net6.0. So this issue is now fixed.
However, the correct fix here is to not use ConsoleLifetime in a WPF app, since it is not a "console app". So implementing your own WpfLifetime is the right idea.
Thanks @eerhardt, but I should clarify the issue here was not the ConsoleLifetime (in fact implementing WpfAppLifetime was a test I've commented above) but the usage of Tasks from the OnApplicationExit event.
ghost locked as resolved and limited conversation to collaborators on Aug 22, 2021
Activity
OAguinagalde commentedon Jun 25, 2020
I found myself in the same situation. My use is pretty much the same:
After calling
Close()on theMainWindowmy methodApplication_Exitis called, and I get this in my logs:Maybe there is a "proper way" of using Microsoft.Extensions and IHost with WPF but I have no idea how to make them both work properly together.
When putting the
_hostin ausingstatement in all of the methods: the constructorApp(),Application_StartupandApplication_Exit, then the problem doesn't happen and the application closes properly, but of course, disposing the IHost right after constructing is definetely not the way to go haha.Any insights on how to make Microsoft.Extensions and WPF work together nicely?
OAguinagalde commentedon Jul 2, 2020
I got some help in the C# Discord, here's a workaround:
For some reason, the StopAsync never actually exits. So, while not a good solution, it works. Still wondering what the proper way would be.
codingdna2 commentedon Jul 3, 2020
Hi, thanks for the workaround. While the workaround works most of the times, it sometimes causes an
ObjectDisposedExceptionin my program.OAguinagalde commentedon Jul 3, 2020
Yeah it's not a good solution, but can't really find any help with how to approach this situation. As for the exception, a good try/catch and that would do it haha.
BrennanConroy commentedon Sep 23, 2020
This looks similar to #35990
Another workaround is to register a different
IHostLifetimethat doesn't block.codingdna2 commentedon Sep 24, 2020
I've tried to implement
IHostLifetimebut as the other solution, theIHostedService(s) are not shutdown gracefully. In fact,IHostLifetime.StopAsyncis never called, as theIHostedService.StopAsyncnever completes.EDIT: Updated sample project with all the relevant parts (IHostLifetime and IHostedService implementations)
Here's my attempt:
mayorovp commentedon Oct 9, 2020
Try this:
Or something like this:
codingdna2 commentedon Oct 12, 2020
Test results, suggested solution 1:
Changed slightly adding
async:Task.Run(async () => await _host.StopAsync()).Wait();but this one ends with an
AggregateException'Remove root: handle=10, parent=01s.WpfTap.Utility.)'containing aTaskCanceledExceptionwhich (I think) referes to the actual task.Test results, suggested solution 2:
Changed slightly adding
async. This one appears to be working as expected! Thanks!Updated sample repo with this fix.
I leave to owners decision to close issue or not.
Suggested fix (see dotnet/runtime#42993)
eerhardt commentedon Jul 22, 2021
With #56057 we no longer block on ProcessExit in the ConsoleLifetime on net6.0. So this issue is now fixed.
However, the correct fix here is to not use ConsoleLifetime in a WPF app, since it is not a "console app". So implementing your own WpfLifetime is the right idea.
codingdna2 commentedon Jul 22, 2021
Thanks @eerhardt, but I should clarify the issue here was not the ConsoleLifetime (in fact implementing WpfAppLifetime was a test I've commented above) but the usage of Tasks from the OnApplicationExit event.