Проблемка в повторных срабатываниях onChange колбека. Проблема наверняка тривиальная для тех кто уже сталкивался. Я сделал минимальный иллюстративный листинг с единственным IOptionsMonitor.
// net9.0 windows10
var host = new HostBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
config.AddCommandLine(args);
})
.ConfigureServices((hostContext, services) =>
{
services.AddLogging(loggingBuilder =>
{
loggingBuilder.AddConsole();
});
services.AddSingleton<IMyClass1, MyClass1>();
services.AddTransient<IMyClass2, MyClass2>();
services.AddTransient<IMyClass3, MyClass3>();
services.Configure<Options1>("Options1", hostContext.Configuration.GetSection("Options1"));
})
.Build();
await host.StartAsync();
public interface IMyClass1
{
// Server interface methods
}
public class MyClass1 : IMyClass1
{
private readonly IMyClass2 _class2;
private readonly IOptionsMonitor<Options1> _optionsMonitor;
private Options1 _options1;
public MyClass1(IMyClass2 myClass2, IOptionsMonitor<Options1> optionsMonitor)
{
_class2 = myClass2;
_optionsMonitor = optionsMonitor;
_options1= _optionsMonitor.CurrentValue;
_optionsMonitor.OnChange((options, name) =>
{
options1 = options;
Console.WriteLine(
$"Options have been changed: Change caused by: {name}" +
$"{Environment.NewLine} - Option1 = {options.Option1}, " +
$"{Environment.NewLine} - Option2 = {options.Option2}, " +
$"{Environment.NewLine} - Option3 = {options.Option3}"
);
Console.WriteLine(Environment.StackTrace);
});
}
}
public interface IMyClass2
{
// TcpListener interface methods
}
public class MyClass2 : IMyClass2
{
private readonly Options1 _options;
public MyClass2(IOptionsSnapshot<Options1> options)
{
_options = options.Value;
}
}
public interface IMyClass3
{
// TcpListener interface methods
}
public class MyClass3 : IMyClass3
{
private readonly Options1 _options;
public MyClass3(IOptionsSnapshot<Options1> options)
{
_options = options.Value;
}
}
public class Options1
{
public string Option1 { get; set; }
public int Option2 { get; set; }
public int Option3 { get; set; }
}
Меняю в appsettings значение ключа, сохраняю.. двойное срабатывание. А иногда однократное.. ощущение что поведение от фаз луны зависит. Стектрейс последнего срабатывания интересен тем, что OnChangeTokenFired в действительно дергается 2 раза. Но почему?
Options have been changed: Change caused by: Options1
- Option1 = hello world,
- Option2 = 222,
- Option3 = 333
at System.Environment.get_StackTrace()
at MyClass1.<.ctor>b__4_0(Options1 options, String name) in E:\workspace\mmoLink-dev\demos\ConsoleApp1\Program.cs:line 90
at Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration`1.OnChangeTokenFired()
at System.Threading.CancellationTokenSource.Invoke(Delegate d, Object state, CancellationTokenSource source)
at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
at Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration`1.OnChangeTokenFired()
at System.Threading.CancellationTokenSource.Invoke(Delegate d, Object state, CancellationTokenSource source)
at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
at Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration`1.OnChangeTokenFired()
at System.Threading.CancellationTokenSource.Invoke(Delegate d, Object state, CancellationTokenSource source)
-- ОТЛИЧИЕ
at System.Threading.CancellationTokenSource.Register(Delegate callback, Object stateForCallback, SynchronizationContext syncContext, ExecutionContext executionContext)
at System.Threading.CancellationToken.Register(Delegate callback, Object state, Boolean useSynchronizationContext, Boolean useExecutionContext)
at System.Threading.CancellationToken.UnsafeRegister(Action`1 callback, Object state)
at Microsoft.Extensions.Internal.ChangeCallbackRegistrar.UnsafeRegisterChangeCallback[T](Action`1 callback, Object state, CancellationToken token, Action`1 onFailure, T onFailureState)
at Microsoft.Extensions.Primitives.CancellationChangeToken.RegisterChangeCallback(Action`1 callback, Object state)
at Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration`1.RegisterChangeTokenCallback(IChangeToken token)
at Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration`1.OnChangeTokenFired()
at System.Threading.CancellationTokenSource.Invoke(Delegate d, Object state, CancellationTokenSource source)
-- ОТЛИЧИЕ
at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()