From 6993b3f0f152a4d00531016a9d24b57a97d0edf1 Mon Sep 17 00:00:00 2001 From: matellush <202132988+matellush@users.noreply.github.com> Date: Fri, 4 Apr 2025 13:23:24 +0200 Subject: [PATCH 1/3] fix: Handle the case of a corrupt JSON config --- WheelWizard/Program.cs | 31 ++++++----- .../Services/Settings/SettingsManager.cs | 4 +- .../Services/Settings/WhWzSettingManager.cs | 53 +++++++++++-------- 3 files changed, 51 insertions(+), 37 deletions(-) diff --git a/WheelWizard/Program.cs b/WheelWizard/Program.cs index f76299f7..f8b149c3 100644 --- a/WheelWizard/Program.cs +++ b/WheelWizard/Program.cs @@ -15,27 +15,32 @@ public class Program [STAThread] public static void Main(string[] args) { - Setup(); + var serviceProvider = BuildServiceProvider(); + + Setup(serviceProvider); // Start the application - BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + BuildAvaloniaApp(serviceProvider).StartWithClassicDesktopLifetime(args); } - // Avalonia configuration, don't remove; also used by visual designer. - // ReSharper disable once MemberCanBePrivate.Global - public static AppBuilder BuildAvaloniaApp() - => ConfigureAvaloniaApp(AppBuilder.Configure() - .UsePlatformDetect() - .WithInterFont() - ); - - private static AppBuilder ConfigureAvaloniaApp(AppBuilder builder) + private static ServiceProvider BuildServiceProvider() { var services = new ServiceCollection(); services.AddWheelWizardServices(); var serviceProvider = services.BuildServiceProvider(); + return serviceProvider; + } + // Avalonia configuration, don't remove; also used by visual designer. + // ReSharper disable once MemberCanBePrivate.Global + public static AppBuilder BuildAvaloniaApp(ServiceProvider serviceProvider) + => ConfigureAvaloniaApp(AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont(), serviceProvider); + + private static AppBuilder ConfigureAvaloniaApp(AppBuilder builder, ServiceProvider serviceProvider) + { // Write startup message var logger = serviceProvider.GetRequiredService>(); LogPlatformInformation(logger); @@ -87,10 +92,10 @@ private static void SetupWorkingDirectory() } } - private static void Setup() + private static void Setup(ServiceProvider serviceProvider) { SetupWorkingDirectory(); - SettingsManager.Instance.LoadSettings(); + SettingsManager.Instance.LoadSettings(serviceProvider); UrlProtocolManager.SetWhWzScheme(); } diff --git a/WheelWizard/Services/Settings/SettingsManager.cs b/WheelWizard/Services/Settings/SettingsManager.cs index 582e6f93..cd8a0b36 100644 --- a/WheelWizard/Services/Settings/SettingsManager.cs +++ b/WheelWizard/Services/Settings/SettingsManager.cs @@ -154,9 +154,9 @@ public class SettingsManager public static SettingsManager Instance { get; } = new(); private SettingsManager() { } // dont make this a static method - public void LoadSettings() + public void LoadSettings(ServiceProvider serviceProvider) { - WhWzSettingManager.Instance.LoadSettings(); + WhWzSettingManager.Instance.LoadSettings(serviceProvider); DolphinSettingManager.Instance.LoadSettings(); SettingsHelper.LoadExtraStuff(); } diff --git a/WheelWizard/Services/Settings/WhWzSettingManager.cs b/WheelWizard/Services/Settings/WhWzSettingManager.cs index 9c39a507..7b428766 100644 --- a/WheelWizard/Services/Settings/WhWzSettingManager.cs +++ b/WheelWizard/Services/Settings/WhWzSettingManager.cs @@ -1,6 +1,8 @@ +using Microsoft.Extensions.Logging; using System.Text.Json; using WheelWizard.Helpers; using WheelWizard.Models.Settings; +using WheelWizard.Views; using JsonElement = System.Text.Json.JsonElement; using JsonSerializerOptions = System.Text.Json.JsonSerializerOptions; @@ -10,25 +12,25 @@ public class WhWzSettingManager { private bool _loaded; private readonly Dictionary _settings = new(); - + public static WhWzSettingManager Instance { get; } = new(); private WhWzSettingManager() { } - + public void RegisterSetting(WhWzSetting setting) { - if (_loaded) + if (_loaded) return; - + _settings.Add(setting.Name, setting); } - + public void SaveSettings(WhWzSetting invokingSetting) { - if (!_loaded) + if (!_loaded) return; - + var settingsToSave = new Dictionary(); - + foreach (var (name, setting) in _settings) { settingsToSave[name] = setting.Get(); @@ -36,10 +38,10 @@ public void SaveSettings(WhWzSetting invokingSetting) var jsonString = JsonSerializer.Serialize(settingsToSave, new JsonSerializerOptions { WriteIndented = true }); FileHelper.WriteAllTextSafe(PathManager.WheelWizardConfigFilePath, jsonString); } - - public void LoadSettings() + + public void LoadSettings(ServiceProvider serviceProvider) { - if (_loaded) + if (_loaded) return; _loaded = true; @@ -47,18 +49,25 @@ public void LoadSettings() var jsonString = FileHelper.ReadAllTextSafe(PathManager.WheelWizardConfigFilePath); if (jsonString == null) return; - jsonString.Trim('\0'); - - var loadedSettings = JsonSerializer.Deserialize>(jsonString); - if (loadedSettings == null) - return; - - foreach (var kvp in loadedSettings) + + try + { + var loadedSettings = JsonSerializer.Deserialize>(jsonString); + if (loadedSettings == null) + return; + + foreach (var kvp in loadedSettings) + { + if (!_settings.TryGetValue(kvp.Key, out var setting)) + continue; + + setting.SetFromJson(kvp.Value); + } + } + catch (JsonException e) { - if (!_settings.TryGetValue(kvp.Key, out var setting)) - continue; - - setting.SetFromJson(kvp.Value); + serviceProvider.GetRequiredService>() + .LogError(e, "Failed to deserialize the JSON config"); } } } From ede57958b1887f79bdb98f134968491fc075e960 Mon Sep 17 00:00:00 2001 From: matellush <202132988+matellush@users.noreply.github.com> Date: Fri, 4 Apr 2025 17:01:29 +0200 Subject: [PATCH 2/3] fix: Always use app service for logging --- WheelWizard/Program.cs | 22 +++++++++---------- .../Services/Settings/SettingsManager.cs | 4 ++-- .../Services/Settings/WhWzSettingManager.cs | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/WheelWizard/Program.cs b/WheelWizard/Program.cs index f8b149c3..e791ed0f 100644 --- a/WheelWizard/Program.cs +++ b/WheelWizard/Program.cs @@ -15,12 +15,10 @@ public class Program [STAThread] public static void Main(string[] args) { - var serviceProvider = BuildServiceProvider(); - - Setup(serviceProvider); - + // Make sure this is the first action on startup! + SetupWorkingDirectory(); // Start the application - BuildAvaloniaApp(serviceProvider).StartWithClassicDesktopLifetime(args); + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); } private static ServiceProvider BuildServiceProvider() @@ -34,13 +32,14 @@ private static ServiceProvider BuildServiceProvider() // Avalonia configuration, don't remove; also used by visual designer. // ReSharper disable once MemberCanBePrivate.Global - public static AppBuilder BuildAvaloniaApp(ServiceProvider serviceProvider) + public static AppBuilder BuildAvaloniaApp() => ConfigureAvaloniaApp(AppBuilder.Configure() .UsePlatformDetect() - .WithInterFont(), serviceProvider); + .WithInterFont()); - private static AppBuilder ConfigureAvaloniaApp(AppBuilder builder, ServiceProvider serviceProvider) + private static AppBuilder ConfigureAvaloniaApp(AppBuilder builder) { + var serviceProvider = BuildServiceProvider(); // Write startup message var logger = serviceProvider.GetRequiredService>(); LogPlatformInformation(logger); @@ -56,6 +55,8 @@ private static AppBuilder ConfigureAvaloniaApp(AppBuilder builder, ServiceProvid // Set the service provider in the application instance app.SetServiceProvider(serviceProvider); + + Setup(); }); return builder; @@ -92,10 +93,9 @@ private static void SetupWorkingDirectory() } } - private static void Setup(ServiceProvider serviceProvider) + private static void Setup() { - SetupWorkingDirectory(); - SettingsManager.Instance.LoadSettings(serviceProvider); + SettingsManager.Instance.LoadSettings(); UrlProtocolManager.SetWhWzScheme(); } diff --git a/WheelWizard/Services/Settings/SettingsManager.cs b/WheelWizard/Services/Settings/SettingsManager.cs index cd8a0b36..582e6f93 100644 --- a/WheelWizard/Services/Settings/SettingsManager.cs +++ b/WheelWizard/Services/Settings/SettingsManager.cs @@ -154,9 +154,9 @@ public class SettingsManager public static SettingsManager Instance { get; } = new(); private SettingsManager() { } // dont make this a static method - public void LoadSettings(ServiceProvider serviceProvider) + public void LoadSettings() { - WhWzSettingManager.Instance.LoadSettings(serviceProvider); + WhWzSettingManager.Instance.LoadSettings(); DolphinSettingManager.Instance.LoadSettings(); SettingsHelper.LoadExtraStuff(); } diff --git a/WheelWizard/Services/Settings/WhWzSettingManager.cs b/WheelWizard/Services/Settings/WhWzSettingManager.cs index 7b428766..692b5c23 100644 --- a/WheelWizard/Services/Settings/WhWzSettingManager.cs +++ b/WheelWizard/Services/Settings/WhWzSettingManager.cs @@ -39,7 +39,7 @@ public void SaveSettings(WhWzSetting invokingSetting) FileHelper.WriteAllTextSafe(PathManager.WheelWizardConfigFilePath, jsonString); } - public void LoadSettings(ServiceProvider serviceProvider) + public void LoadSettings() { if (_loaded) return; @@ -66,7 +66,7 @@ public void LoadSettings(ServiceProvider serviceProvider) } catch (JsonException e) { - serviceProvider.GetRequiredService>() + App.Services.GetRequiredService>() .LogError(e, "Failed to deserialize the JSON config"); } } From a071b3584df0f42a05b706fd63ee8a7367cce13b Mon Sep 17 00:00:00 2001 From: matellush <202132988+matellush@users.noreply.github.com> Date: Fri, 4 Apr 2025 17:21:45 +0200 Subject: [PATCH 3/3] docs: Add comment explaining the order of the setup --- WheelWizard/Program.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WheelWizard/Program.cs b/WheelWizard/Program.cs index e791ed0f..c4db8afa 100644 --- a/WheelWizard/Program.cs +++ b/WheelWizard/Program.cs @@ -56,6 +56,9 @@ private static AppBuilder ConfigureAvaloniaApp(AppBuilder builder) // Set the service provider in the application instance app.SetServiceProvider(serviceProvider); + // Make sure this comes AFTER setting the service provider + // of the `App` instance! Otherwise, things like logging will not work + // in `Setup`. Setup(); });