Задать вопрос
iamkisly
@iamkisly
Собираю админки на dotnet и extjs

В чем причина повторного срабатывания IOptionsMonitor.onChange?

Проблемка в повторных срабатываниях 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()
  • Вопрос задан
  • 32 просмотра
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы