Asp.net core能夠監視json、xml等配置文件的變化, 自動刷新內存中的配置內容, 但若是想每隔1秒從zookeeper、consul獲取最新的配置信息, 須要本身實現.json
閱讀了 Asp.net core Document的Custom configuration provider, 得知只須要實現本身的IConfigurationSource和對應ConfigurationProvider便可api
在這個示例中, 我創建了一個簡單的option, 只包含一個不斷變化的計數器變量.ide
public class RefreshableOptions { public int IncreasementCount { get; set; } }
實現IConfigurationSource和對應ConfigurationProvider, 內部有一個timer模擬從外部獲取了最新的數據, 這裏爲簡單起見, 採用硬編碼的方式指定了option的路徑ui
public class AutoRefreshConfigurationSource : IConfigurationSource { public IConfigurationProvider Build(IConfigurationBuilder builder) { return new AutoRefreshConfigurationProvider(); } } public class AutoRefreshConfigurationProvider : ConfigurationProvider { private int count = 0; private bool isChanged; public AutoRefreshConfigurationProvider() : base() { Timer timer = new Timer(TimerCallback); timer.Change(1000, 3000); } public override void Load() { var beforeData = Data; // 這裏採用硬編碼指定option的路徑 Data = new Dictionary<string, string>() { { "AutoRefreshOptions:IncreasementCount", count.ToString() } }; isChanged = IsDictionaryChanged(beforeData, Data); } private void TimerCallback(object state) { count++; this.Load(); if (isChanged) { base.OnReload();//通知IConfiguration實例, 有參數發生了改變 isChanged = false; } } //判斷兩個Idictionary是否有不一樣的幫助方法 private static bool IsDictionaryChanged(IDictionary<string, string> before, IDictionary<string, string> after) { if (before == null && after == null) { return false; } if ((before == null) != (after == null)) { return true; } if (before.Count != after.Count) { return true; } var ignoreCaseBefore = new Dictionary<string, string>(before, StringComparer.OrdinalIgnoreCase); foreach (var afterItemKey in after.Keys) { if (!ignoreCaseBefore.TryGetValue(afterItemKey, out var beforeItemValue)) { return true; } if (beforeItemValue != after[afterItemKey]) { return true; } ignoreCaseBefore.Remove(afterItemKey); } if (ignoreCaseBefore.Count > 0) { return true; } return false; } }
實現擴展方法this
public static class AutoRereshConfigurationExtensions { public static IConfigurationBuilder AddAutoRereshConfiguration(this IConfigurationBuilder builder) { return builder.Add(new AutoRefreshConfigurationSource()); } }
使用方法編碼
新建一個WebApi項目, 在Program.CreateWebHostBuilder中增長黃色部分spa
WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration(config => { config.AddAutoRereshConfiguration(); }) .UseStartup<Startup>();
在Startup. ConfigureServices中配置.net
services.Configure<RefreshableOptions>(Configuration.GetSection("AutoRefreshOptions"));
修改ValuesControllercode
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { private RefreshableOptions refreshableOptions; public ValuesController(IOptionsSnapshot<RefreshableOptions> refreshableOptions) { this.refreshableOptions = refreshableOptions.Value; } [HttpGet] public ActionResult<IEnumerable<string>> Get() { return new string[] { "value1", "value2", refreshableOptions.IncreasementCount.ToString() }; } }
啓動後不停的刷新http://localhost:5000/api/values能夠看到返回內容的變化xml
後記: 這個功能寫得比較早, 後來在nuget上發現不少consul configure的擴展, 這段代碼就全當練習吧.