TaskCanceledException in ShutDownListener
There seems to be a workaround, at least for .NET Framework 4.7.2
https://github.com/Microsoft/dotnet/blob/master/Documentation/compatibility/wpf-AppDomain-shutdown-handling-may-now-call-Dispatcher.Invoke-in-cleanup-of-WeakEvents.md
Change Description
In .NET Framework 4.7.1 and earlier versions, WPF potentially creates a System.Windows.Threading.Dispatcher
on the .NET finalizer thread during AppDomain
shutdown. This was fixed in .NET Framework 4.7.2 and later versions by making the cleanup of weak events thread-aware. Due to this, WPF may call System.Windows.Threading.Dispatcher.Invoke
to complete the cleanup process.
In certain applications, this change in finalizer timing can potentially cause exceptions during AppDomain
or process shutdown. This is generally seen in applications that do not correctly shut down dispatchers running on worker threads prior to process or AppDomain
shutdown. Such applications should take care to properly manage the lifetime of dispatchers.
Recommended Action
In .NET Framework 4.7.2 and later versions, developers can disable this fix in order to help alleviate (but not eliminate) timing issues that may occur due to the cleanup change.
To disable the change in cleanup, use the following AppContext
flag.
<configuration>
<runtime>
<AppContextSwitchOverrides value="Switch.MS.Internal.DoNotInvokeInWeakEventTableShutdownListener=true"/>
</runtime>
</configuration>
I've been seeing this too. There's an arbitrary 300ms time limit during shutdown if you look at the source ~278: https://referencesource.microsoft.com/#WindowsBase/Base/MS/Internal/WeakEventTable.cs
try
{
Dispatcher.Invoke((Action)OnShutDown, DispatcherPriority.Send, CancellationToken.None, TimeSpan.FromMilliseconds(300));
succeeded = true;
}
catch (TimeoutException)
{
}
It raises even though the internal collections in the WeakEventTable are all emptied out.
Whoever wrote it didn't anticipate the runtime throwing TaskCanceledException
since probably it never used to. The workaround I'm taking is to remove all use of WeakEventManager.