Podczas implementowania jednego z ficzerów aplikacji w pracy popełniłem metodę, w której uruchomiłem asynchroniczną metodę bez awaita.
Metoda miała i tak być odpalona w trybie „Fire and forget” więc uznałem wpisywanie tych kilkunastu znaków za stratę czasu i puściłem moduł na testy, które to testy moduł przeszedł. Jednak w przeciągu tygodnia użytkownicy zaczęli się skarżyć że aplikacja się przewraca w losowych momentach. Logi wskazywały, że mechanizm globalnej obsługi wyjątków loguje błąd o szczegółach podobnych do następujących:
Stack trace:
Caused by:
Message:Zgłoszono wyjątek typu 'System.Exception’.
Stack trace:
Niewiele da się z tego odczytać. Uratował mnie jednak fakt iż typ wyjątku był mi bardzo dobrze znany (i nie był to System.Exception).
Dodanie awaita sprawiło, że stos zaczął wyglądać po ludzku:
Stack trace:
w System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
w System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
w Szogun1987.TaskExceptions.MainWindow.<WithAwaitAndCompletionSource_Click>d__3.MoveNext() w D:\Projekty\Szogun1987.TaskExceptions\src\Szogun1987.TaskExceptions\Szogun1987.TaskExceptions\MainWindow.xaml.cs:wiersz 30
— Koniec śladu stosu z poprzedniej lokalizacji, w której wystąpił wyjątek —
w System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0(Object state)
w System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
w System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
Przygotowałem też programik obrazujący problem: https://github.com/szogun1987/TaskExceptions
Błąd wykazuje największą powtarzalność po zbudowaniu w wersji Release. Gdyby błąd nie chciał wystąpić należy wcisnąć przycisk GC.Collect.