ChangeToken.OnChange不会在自定义配置提供程序上触发

问题描述 投票:2回答:2

我将尝试创建将从数据库中获取密钥的自定义配置提供程序。正如手册中所写,我创建了这个提供程序并且它的工作正常。所有键都在启动时加载,一切正常。

但是现在我正在尝试使用IOptionsSnapshot并重新加载来自db的密​​钥。但没有任何反应。

谁能告诉我作品出错了。这是我的代码:

    public class EFConfigProvider : ConfigurationProvider
{
    private DateTime lastLoaded;
    public EFConfigProvider(Action<DbContextOptionsBuilder> optionsAction)
    {
        OptionsAction = optionsAction;
        lastLoaded = DateTime.Now;
        ChangeToken.OnChange(
            () => Watch(),
            () => {
                Thread.Sleep(250);
                this.Load();
            });
    }

    public new IChangeToken GetReloadToken()
    {
        return Watch();
    }

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    // Load config data from EF DB.
    public override void Load()
    {
        this.Data.Clear();

        var builder = new DbContextOptionsBuilder<ConfigContext>();
        OptionsAction(builder);

        using (var dbContext = new ConfigContext(builder.Options))
        {
            // Save Load Fact
            dbContext.SaveLoadFact();
            // Load Partners Settings
            GetPartners(dbContext);
        }
    }

    private IChangeToken Watch()
    {
        return new DatabaseChangeToken();
    }
}

public class DatabaseChangeToken : IChangeToken
{
    public bool HasChanged
    {
        get
        {
            return true;
        }
    }
    public bool ActiveChangeCallbacks => false;

    public IDisposable RegisterChangeCallback(Action<object> callback, object state) => EmptyDisposable.Instance;

    internal class EmptyDisposable : IDisposable
    {
        public static EmptyDisposable Instance { get; } = new EmptyDisposable();
        private EmptyDisposable() { }
        public void Dispose() { }
    }
}

我做了什么开始工作:

  1. 我在类EFConfigProvider变量中添加
private ConfigurationReloadToken _reloadToken = new ConfigurationReloadToken();
  1. 我添加了构造函数
// Start Periodic task to refresh the DB
        PeriodicTask.Run(() =>
        {
            //Refresh();
            OnReload();
        }, TimeSpan.FromSeconds(reload));
  1. 我为periodTask添加了类
public class PeriodicTask
{
    public static async Task Run(Action action, TimeSpan period, CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            await Task.Delay(period, cancellationToken);

            if (!cancellationToken.IsCancellationRequested)
                action();
        }
    }

    public static Task Run(Action action, TimeSpan period)
    {
        return Run(action, period, CancellationToken.None);
    }
}
  1. 在Reload上添加方法
protected new void OnReload()
        {
            var previousToken = Interlocked.Exchange(ref _reloadToken, new ConfigurationReloadToken());
            previousToken.OnReload();
        }
  1. 添加使用更改令牌的更改
  ChangeToken.OnChange(
                () => { return this._reloadToken; },
                () => {
                    Thread.Sleep(250);
                    this.Load();
                });
c# asp.net-core configuration
2个回答
-2
投票

我有相同的要求,我达到了你的代码,我尝试了同样的事情,没有工作。

但是你的代码和其他一些调查引导我提示。

public class CustomConfigurationProvider : ConfigurationProvider
{
    private readonly string applicationName;
    private readonly bool reloadOnChange;
    private readonly IConfiguration configuration;

    public CustomConfigurationProvider(string applicationName, bool reloadOnChange)
    {
        this.applicationName = applicationName;
        this.reloadOnChange = reloadOnChange;

        if(reloadOnChange)
        {
        ChangeToken.OnChange(
            () => GetReloadToken(), // listener to token change
            () =>
            {
                Thread.Sleep(250);
                this.Load();
            });
        }
    }

    public override async void Load()
    {
        Data.Clear();

        Data = read data from database;

        if (Condition to check if data in database changed)
        {
            OnReload(); // This will create new token and trigger change so what is register in OnChange above will be called again which is this.Load()
        }
    }
}

我也提到了qazxsw poi

https://www.mikesdotnetting.com/article/301/loading-asp-net-core-mvc-views-from-a-database-or-other-location

希望这可以帮助。


0
投票

更新:我发现重写https://docs.microsoft.com/en-us/aspnet/core/fundamentals/primitives/change-tokens打破了变化的通知(我使用OnReload(),没有看到变化)。所以我改变了我的实现,不这样做。它调用默认的OptionsMonitor来处理OnReload()变化的通知。


您更新的实施确实帮助了我,谢谢!

但不是使用您的自定义OptionsMonitor,您可以使用PeriodicTask。但效果却是一样的。

这是我的实现,每5分钟重新加载一次数据:

Timer
© www.soinside.com 2019 - 2024. All rights reserved.