.Net Core中的令牌ChangeToken、IChangeToken介绍

ChangeToken是个静态类:

public static class ChangeToken
{
    public static IDisposable OnChange(Func<IChangeToken> changeTokenProducer, Action changeTokenConsumer);
}

该类仅仅提供了一个OnChange的静态方法,而该方法需要一个返回类型为IChangeToken的参数。而一看这个命名**Token,是不是很像CancellationToken,拥有了它,就会得到通知。 这种东西官方的名称其实叫做“令牌”。所以,您可能都会猜到,它可能会具有一个注册回调的方法:

public interface IChangeToken
{
    bool HasChanged { get; }
    bool ActiveChangeCallbacks { get; }

    IDisposable RegisterChangeCallback(Action<object> callback, object state);
}

那么,它存在的意义是什么呢? 高层的抽象! 

比如下方的代码:

Console.WriteLine("开始监测文件夹 c:\temp");

var phyFileProvider = new PhysicalFileProvider("c:\temp");
IChangeToken changeToken = phyFileProvider.Watch("*.*");
changeToken.RegisterChangeCallback(_ =>
{
    Console.WriteLine("检测到文件夹有变化!" + _);
}, "xiaoming");

像不像一个叫做PhysicalFileProvider的运营商,给我发了一个令牌。当我拥有这个令牌之后,运营商就可以联系到我了,当它联系我的时候,我就可以做出对应的反应。比如上面是打印一排字出来。

而在“物理文件”这个圈子里面,IChangeToken的真身叫做PollingFileChangeToken;

在“配置系统”这个圈子里面,IChangeToken的真身叫做ConfigurationReloadToken

如果咱们想实现自己的IChangeToken怎么办呢?还记得最上面的CancellationTokenSource吗?既然.Net为咱们提供了一个线程安全而又直接可以拿来用的工具:

public class MyOwnChangeToken : IChangeToken
{
    public CancellationTokenSource _cts = new CancellationTokenSource();

    public bool ActiveChangeCallbacks => true;

    public bool HasChanged => _cts.IsCancellationRequested;

    public IDisposable RegisterChangeCallback(Action<object> callback, object state) => _cts.Token.Register(callback, state);

    public void MyOwnChange() => _cts.Cancel();
}

在“我自己的这个圈子”,就可以使用MyOwnChangeToken了,当外界获取到我的IChangeToken,我就可以触发MyOwnChange来通知他们了。

其实.NET Core中大部分的IChangeToken内部都使用了CancellationTokenSource

搞懂了IChangeToken我们就很轻松就能理解了ChangeToken,作为静态类的它,肯定是作为一个工具类的实现。

 ChangeToken.OnChange(
    () => physicalFileProvider.Watch("*.*"),
    () => Console.WriteLine("检测到文件夹有变化!")
);

那么您可能会说,我直接使用pysicalFileProvider.Watch()方法返回的IChangeToken的RegisterChangeCallback方法订阅不行吗?他们有什么区别吗? 答案是:“调用次数”。使用RegisterChangeCallback的方法,只会执行一次回调内容,因为当“令牌”用了一次之后,其实它就失效了。所以上面那个监控文件改动的代码,当第二次文件改动的时候,它其实是不会再执行回调的。

而使用ChangeToken这个静态类,它就可以帮助您不断的去获取新“令牌”然后注册对应的回调,所以就能够保证咱们多次改变也能触发回调了。

所以来看上面的这一段代码 ChangeToken.OnChange(() => physicalFileProvider.Watch("*.*"),...),“phyFileProvider”这个“供应商”可以为我们提供“令牌”,当该令牌发生改动的时候,我们就有机会去完成操作了。

() => physicalFileProvider.Watch("*.*")这部分代码我们可以称它为“令牌生产过程”,而() => Console.WriteLine("检测到文件夹有变化!")叫做“令牌的消费过程”。

ChangeToken 干的事情就是:当消费者消费之后,就又会去让“生产过程”再生成一个令牌出来,并且在该令牌上挂载“消费过程”,这样就能保证能够一直“观察”下去了。

案例1:添加缓存时提供IChangeToken,当依赖文件修改时,删除缓存

var fileProvider = new PhysicalFileProvider(Path.GetDirectoryName(dependencyFile));
var changeToken = fileProvider.Watch(Path.GetFileName(dependencyFile));
cache.Set(key, value, new MemoryCacheEntryOptions().AddExpirationToken(changeToken);

案例2:配置文件统一读取类,当配置文件修改时,利用ChangeToken重新读取配置

    public class ConfigSetting
    {
        private IConfiguration _configuration = null;
        public ConfigSetting(IConfiguration configuration)
        {
            _configuration = configuration;
            ChangeToken.OnChange(()=>configuration.GetReloadToken(), () =>
            {
                reloadConfiguration();
            });
            reloadConfiguration();
        }
        private void reloadConfiguration()
        {
            _siteName = _configuration["SiteName"];
            _siteID = _configuration.GetValue<int>("SiteID");
        }

        private string _siteName = null;
        private int _siteID = 0;
        public string SiteName
        {
            get{return _siteName;            }
        }
        public int SiteID
        {
            get{return _siteID;            }
        }
    }

 

参考:https://www.cnblogs.com/uoyo/p/12509871.html

原文地址:https://www.cnblogs.com/fanfan-90/p/12772732.html