Skip to content

[Code Quality] Servy.Manager XAML code-behind — async void event handlers swallow exceptions #713

@Christophe-Rogiers

Description

@Christophe-Rogiers

Severity: Warning

Files and lines:

  • src/Servy.Manager/Views/MainWindow.xaml.cs lines 49, 59, 105, 136, 155
  • src/Servy.Manager/Views/ConsoleView.xaml.cs lines 196, 217
  • src/Servy.Manager/Views/PerformanceView.xaml.cs lines 33, 54
  • src/Servy.Manager/Views/DependenciesView.xaml.cs lines 33, 54

Description:
Eleven WPF event handlers across four code-behind files are declared private async void. When any await inside them throws, the exception is raised on the SynchronizationContext; by default this either terminates the WPF app via DispatcherUnhandledException or — depending on wiring — disappears. Either way the failure is not observable on a returned Task and is hard to correlate with the originating user gesture (tab switch, Window_Loaded, SearchTextBox_KeyDown, Menu_ConfigClik).

// MainWindow.xaml.cs:155
private async void MainTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    try { ... } catch (Exception ex) { ... }
}

Some handlers already have a defensive try/catch, but several (e.g. Window_Loaded calling await vm.SearchCommand.ExecuteAsync(null)) do not, and even where a catch exists the handler still fundamentally can't surface its completion/failure to callers or tests.

Suggested fix:
Prefer ICommand bindings so the async work lives on the ViewModel (AsyncCommand/RelayCommand<T>), which gives you an awaitable Task for testing and exception routing. Where a code-behind handler is unavoidable, route through a tiny helper:

private void Window_Loaded(object sender, RoutedEventArgs e) => _ = Window_LoadedAsync(sender, e);

private async Task Window_LoadedAsync(object sender, RoutedEventArgs e)
{
    try { if (DataContext is MainViewModel vm) await vm.SearchCommand.ExecuteAsync(null); }
    catch (Exception ex) { Logger.Error(nameof(Window_LoadedAsync), ex); }
}

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions