Asp.net core可以监视json、xml等配置文件的变化, 自动刷新内存中的配置内容, 但如果想每隔1秒从zookeeper、consul获取最新的配置信息, 需要自己实现.

阅读了 Asp.net core Document的Custom configuration provider, 得知只需要实现自己的IConfigurationSource和对应ConfigurationProvider即可

在这个示例中, 我建立了一个简单的option, 只包含一个不断变化的计数器变量.

?

1
2
3
4
public class RefreshableOptions
{
  public int IncreasementCount { get; set; }
}

实现IConfigurationSource和对应ConfigurationProvider, 内部有一个timer模拟从外部获取了最新的数据, 这里为简单起见, 采用硬编码的方式指定了option的路径

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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;
  }
}

实现扩展方法

?

1
2
3
4
5
6
7
public static class AutoRereshConfigurationExtensions
{
  public static IConfigurationBuilder AddAutoRereshConfiguration(this IConfigurationBuilder builder)
  {
    return builder.Add(new AutoRefreshConfigurationSource());
  }
}

使用方法

新建一个WebApi项目, 在Program.CreateWebHostBuilder中增加黄色部分

?

1
2
3
4
5
6
WebHost.CreateDefaultBuilder(args)
  .ConfigureAppConfiguration(config =>
  {
    config.AddAutoRereshConfiguration();
  })
  .UseStartup<Startup>();

在Startup. ConfigureServices中配置

?

1
services.Configure<RefreshableOptions>(Configuration.GetSection("AutoRefreshOptions"));

修改ValuesController

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[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可以看到返回内容的变化


评论(0条)

请登录后评论
wxz1425255448

wxz1425255448

0

0

0

( 此人很懒并没有留下什么~~ )