From d866c085fde663bc88e975afdb67e5f45bd5e36d Mon Sep 17 00:00:00 2001 From: Adam Simon Date: Fri, 29 May 2026 22:53:40 +0200 Subject: [PATCH 1/2] Fix incorrect registration of user configuration actions in generic AddJsonFile overloads --- .../JsonFileLoggerExtensions.cs | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/source/FileLogger.Json/JsonFileLoggerExtensions.cs b/source/FileLogger.Json/JsonFileLoggerExtensions.cs index 84c1fc3..ff5df23 100644 --- a/source/FileLogger.Json/JsonFileLoggerExtensions.cs +++ b/source/FileLogger.Json/JsonFileLoggerExtensions.cs @@ -99,11 +99,16 @@ public static ILoggingBuilder AddJsonFile< Action? configure = null, string? optionsName = null) where TProvider : FileLoggerProvider { + if (builder is null) + throw new ArgumentNullException(nameof(builder)); + + optionsName ??= typeof(TProvider).ToString(); + builder.AddFile(context, configure: null, optionsName) - .ConfigureTextBuilder(textBuilder ?? JsonFileLogEntryTextBuilder.Default, optionsName ?? typeof(TProvider).ToString()); + .ConfigureTextBuilder(textBuilder ?? JsonFileLogEntryTextBuilder.Default, optionsName); if (configure is not null) - builder.Services.Configure(configure); + builder.Services.Configure(optionsName, configure); return builder; } @@ -125,11 +130,16 @@ public static ILoggingBuilder AddJsonFile< where TProvider : FileLoggerProvider where TOptions : FileLoggerOptions { + if (builder is null) + throw new ArgumentNullException(nameof(builder)); + + optionsName ??= typeof(TProvider).ToString(); + builder.AddFile(context, configure: null, optionsName) - .ConfigureTextBuilder(textBuilder ?? JsonFileLogEntryTextBuilder.Default, optionsName ?? typeof(TProvider).ToString()); + .ConfigureTextBuilder(textBuilder ?? JsonFileLogEntryTextBuilder.Default, optionsName); if (configure is not null) - builder.Services.Configure(configure); + builder.Services.Configure(optionsName, configure); return builder; } @@ -145,11 +155,16 @@ public static ILoggingBuilder AddJsonFile< where TProvider : FileLoggerProvider where TOptions : FileLoggerOptions { + if (builder is null) + throw new ArgumentNullException(nameof(builder)); + + optionsName ??= typeof(TProvider).ToString(); + builder.AddFile(bindOptions, context, configure: null, optionsName) - .ConfigureTextBuilder(textBuilder ?? JsonFileLogEntryTextBuilder.Default, optionsName ?? typeof(TProvider).ToString()); + .ConfigureTextBuilder(textBuilder ?? JsonFileLogEntryTextBuilder.Default, optionsName); if (configure is not null) - builder.Services.Configure(configure); + builder.Services.Configure(optionsName, configure); return builder; } From a8a1bcd679f6e438e6179fc26844e7d18bc48d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerrit=20G=C3=B6tzen?= Date: Sun, 31 May 2026 00:44:51 +0200 Subject: [PATCH 2/2] Add regression tests for generic AddJsonFile named options The generic AddJsonFile overloads must apply the user configuration callback to the named options instance that the provider resolves via IOptionsMonitor.Get(optionsName). Before the fix the callback was registered against Options.DefaultName, so it never reached the provider's own options (adams85/filelogger#39). Each of the three affected overloads is pinned independently: the tests fail against the pre-fix source and pass with the fix (adams85/filelogger#40). Co-Authored-By: Claude Opus 4.8 --- test/FileLogger.Test/SettingsTest.cs | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/FileLogger.Test/SettingsTest.cs b/test/FileLogger.Test/SettingsTest.cs index 3868467..e9e10e4 100644 --- a/test/FileLogger.Test/SettingsTest.cs +++ b/test/FileLogger.Test/SettingsTest.cs @@ -381,4 +381,54 @@ static string BuildConfigJson(LogLevel defaultProviderLevel, LogLevel otherProvi "" }, lines); } + + private static void AssertUserConfigurationAppliesToNamedOptions( + Action configureLogging, string optionsName, string expectedBasePath) + { + var services = new ServiceCollection(); + services.AddLogging(configureLogging); + + using ServiceProvider serviceProvider = services.BuildServiceProvider(); + + // The provider resolves its settings via IOptionsMonitor.Get(optionsName), so the user + // configuration callback must be applied to the named options instance, not Options.DefaultName. + IOptionsMonitor optionsMonitor = + serviceProvider.GetRequiredService>(); + + Assert.Equal(expectedBasePath, optionsMonitor.Get(optionsName).BasePath); + Assert.NotEqual(expectedBasePath, optionsMonitor.Get(Options.DefaultName).BasePath); + } + + [Fact] + public void Issue39_GenericAddJsonFileAppliesUserConfigurationToNamedOptions() + { + const string optionsName = "MyJsonProvider"; + const string basePath = "some-sentinel-base-path"; + + AssertUserConfigurationAppliesToNamedOptions( + lb => lb.AddJsonFile(configure: o => o.BasePath = basePath, optionsName: optionsName), + optionsName, basePath); + } + + [Fact] + public void Issue39_GenericAddJsonFileWithOptionsAppliesUserConfigurationToNamedOptions() + { + const string optionsName = "MyJsonProvider"; + const string basePath = "some-sentinel-base-path"; + + AssertUserConfigurationAppliesToNamedOptions( + lb => lb.AddJsonFile(configure: o => o.BasePath = basePath, optionsName: optionsName), + optionsName, basePath); + } + + [Fact] + public void Issue39_GenericAddJsonFileWithBindOptionsAppliesUserConfigurationToNamedOptions() + { + const string optionsName = "MyJsonProvider"; + const string basePath = "some-sentinel-base-path"; + + AssertUserConfigurationAppliesToNamedOptions( + lb => lb.AddJsonFile(bindOptions: (o, c) => { }, configure: o => o.BasePath = basePath, optionsName: optionsName), + optionsName, basePath); + } }