Asp. net core method example for implementing automatically updated Option
- 2021-11-02 00:35:26
- OfStack
Asp. net core can monitor the changes of json, xml and other configuration files, and automatically refresh the configuration contents in memory. However, if you want to get the latest configuration information from zookeeper and consul every 1 second, you need to implement it yourself.
After reading Asp. net core Document Custom configuration provider, I learned that I only need to implement my own IConfigurationSource and corresponding ConfigurationProvider
In this example, I set up a simple option that contains only one ever-changing counter variable.
public class RefreshableOptions
{
public int IncreasementCount { get; set; }
}
Realize IConfigurationSource and corresponding ConfigurationProvider. There is an timer simulation inside to get the latest data from outside. For the sake of simplicity, the path of option is specified by hard coding
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;
// Hard-coded specification here option Path of
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();// Notice IConfiguration Instances , Some parameters have changed
isChanged = false;
}
}
// Judge two Idictionary Are there different ways to help
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;
}
}
Implement the extension method
public static class AutoRereshConfigurationExtensions
{
public static IConfigurationBuilder AddAutoRereshConfiguration(this IConfigurationBuilder builder)
{
return builder.Add(new AutoRefreshConfigurationSource());
}
}
Usage
Create a new WebApi project and add yellow part in Program. CreateWebHostBuilder
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config =>
{
config.AddAutoRereshConfiguration();
})
.UseStartup<Startup>();
Configured in Startup. ConfigureServices
services.Configure<RefreshableOptions>(Configuration.GetSection("AutoRefreshOptions"));
Modify ValuesController
[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() };
}
}
Refresh http://localhost: 5000/api/values after startup to see the change of returned content
Text code