Asp.net core 手动触发IOptionsMonitor<>;。一旦改变

Asp.net core 手动触发IOptionsMonitor<>;。一旦改变,asp.net-core,configuration,settings,Asp.net Core,Configuration,Settings,在ASP.NET Core 2.1中,我使用IOptionsMonitor并对其进行设置,以便在更改appSettings.json文件时成功获取事件。所以这是有效的 我现在想做的是,通过代码手动更改选项中的一些值,并触发所有监视器。这可能吗?对于IOptionsMonitor,它只会更改内存中的值,而不会保存回appsettings.json。为了解决这个问题,您需要实现自己的方法将更改保存回appsettings.json 定义从IOptions继承的IWritableOptions pu

在ASP.NET Core 2.1中,我使用IOptionsMonitor并对其进行设置,以便在更改appSettings.json文件时成功获取事件。所以这是有效的

我现在想做的是,通过代码手动更改选项中的一些值,并触发所有监视器。这可能吗?

对于
IOptionsMonitor
,它只会更改内存中的值,而不会保存回
appsettings.json
。为了解决这个问题,您需要实现自己的方法将更改保存回
appsettings.json

  • 定义从
    IOptions继承的
    IWritableOptions

    public interface IWritableOptions<out T> : IOptions<T> where T : class, new()
    {
         void Update(Action<T> applyChanges);
    }
    
    public class WritableOptions<T> : IWritableOptions<T> where T : class, new()
    {
    private readonly IHostingEnvironment _environment;
    private readonly IOptionsMonitor<T> _options;
    private readonly IConfigurationRoot _configuration;
    private readonly string _section;
    private readonly string _file;
    
    public WritableOptions(
        IHostingEnvironment environment,
        IOptionsMonitor<T> options,
        IConfigurationRoot configuration,
        string section,
        string file)
    {
        _environment = environment;
        _options = options;
        _configuration = configuration;
        _section = section;
        _file = file;
    }
    
    public T Value => _options.CurrentValue;
    public T Get(string name) => _options.Get(name);
    
    public void Update(Action<T> applyChanges)
    {
        var fileProvider = _environment.ContentRootFileProvider;
        var fileInfo = fileProvider.GetFileInfo(_file);
        var physicalPath = fileInfo.PhysicalPath;
    
        var jObject = JsonConvert.DeserializeObject<JObject>(File.ReadAllText(physicalPath));
        var sectionObject = jObject.TryGetValue(_section, out JToken section) ?
            JsonConvert.DeserializeObject<T>(section.ToString()) : (Value ?? new T());
    
        applyChanges(sectionObject);
    
        jObject[_section] = JObject.Parse(JsonConvert.SerializeObject(sectionObject));
        File.WriteAllText(physicalPath, JsonConvert.SerializeObject(jObject, Formatting.Indented));
        _configuration.Reload();
    }
    }
    
  • 配置
    IWritableOptions

    public static class ServiceCollectionExtensions
    {
    public static void ConfigureWritable<T>(
        this IServiceCollection services,
        IConfigurationSection section,
        string file = "appsettings.json") where T : class, new()
    {
        services.Configure<T>(section);
        services.AddTransient<IWritableOptions<T>>(provider =>
        {
            var configuration = (IConfigurationRoot)provider.GetService<IConfiguration>();
            var environment = provider.GetService<IHostingEnvironment>();
            var options = provider.GetService<IOptionsMonitor<T>>();
            return new WritableOptions<T>(environment, options, configuration, section.Key, file);
        });
    }
    }
    
  • 使用

    public class OptionsController : Controller
    {
    private readonly IWritableOptions<Locations> _writableLocations;
    public OptionsController(IWritableOptions<Locations> writableLocations)
    {
        _writableLocations = writableLocations;
    }
    
    public IActionResult Change(string value)
    {
        _writableLocations.Update(opt => {
            opt.Name = value;
        });
        return Ok("OK");
    }
    }
    
    公共类选项控制器:控制器
    {
    私有只读IWritableOptions\u writableLocations;
    公共选项控制器(IWritableOptions可写位置)
    {
    _writableLocations=可写位置;
    }
    公共IActionResult更改(字符串值)
    {
    _writableLocations.Update(opt=>{
    opt.Name=值;
    });
    返回Ok(“Ok”);
    }
    }
    
  • 它将触发
    IOptionsMonitor.OnChange

对于
IOptionsMonitor
,它只更改内存中的值,而不保存回
appsettings.json
。为了解决这个问题,您需要实现自己的方法将更改保存回
appsettings.json

  • 定义从
    IOptions继承的
    IWritableOptions

    public interface IWritableOptions<out T> : IOptions<T> where T : class, new()
    {
         void Update(Action<T> applyChanges);
    }
    
    public class WritableOptions<T> : IWritableOptions<T> where T : class, new()
    {
    private readonly IHostingEnvironment _environment;
    private readonly IOptionsMonitor<T> _options;
    private readonly IConfigurationRoot _configuration;
    private readonly string _section;
    private readonly string _file;
    
    public WritableOptions(
        IHostingEnvironment environment,
        IOptionsMonitor<T> options,
        IConfigurationRoot configuration,
        string section,
        string file)
    {
        _environment = environment;
        _options = options;
        _configuration = configuration;
        _section = section;
        _file = file;
    }
    
    public T Value => _options.CurrentValue;
    public T Get(string name) => _options.Get(name);
    
    public void Update(Action<T> applyChanges)
    {
        var fileProvider = _environment.ContentRootFileProvider;
        var fileInfo = fileProvider.GetFileInfo(_file);
        var physicalPath = fileInfo.PhysicalPath;
    
        var jObject = JsonConvert.DeserializeObject<JObject>(File.ReadAllText(physicalPath));
        var sectionObject = jObject.TryGetValue(_section, out JToken section) ?
            JsonConvert.DeserializeObject<T>(section.ToString()) : (Value ?? new T());
    
        applyChanges(sectionObject);
    
        jObject[_section] = JObject.Parse(JsonConvert.SerializeObject(sectionObject));
        File.WriteAllText(physicalPath, JsonConvert.SerializeObject(jObject, Formatting.Indented));
        _configuration.Reload();
    }
    }
    
  • 配置
    IWritableOptions

    public static class ServiceCollectionExtensions
    {
    public static void ConfigureWritable<T>(
        this IServiceCollection services,
        IConfigurationSection section,
        string file = "appsettings.json") where T : class, new()
    {
        services.Configure<T>(section);
        services.AddTransient<IWritableOptions<T>>(provider =>
        {
            var configuration = (IConfigurationRoot)provider.GetService<IConfiguration>();
            var environment = provider.GetService<IHostingEnvironment>();
            var options = provider.GetService<IOptionsMonitor<T>>();
            return new WritableOptions<T>(environment, options, configuration, section.Key, file);
        });
    }
    }
    
  • 使用

    public class OptionsController : Controller
    {
    private readonly IWritableOptions<Locations> _writableLocations;
    public OptionsController(IWritableOptions<Locations> writableLocations)
    {
        _writableLocations = writableLocations;
    }
    
    public IActionResult Change(string value)
    {
        _writableLocations.Update(opt => {
            opt.Name = value;
        });
        return Ok("OK");
    }
    }
    
    公共类选项控制器:控制器
    {
    私有只读IWritableOptions\u writableLocations;
    公共选项控制器(IWritableOptions可写位置)
    {
    _writableLocations=可写位置;
    }
    公共IActionResult更改(字符串值)
    {
    _writableLocations.Update(opt=>{
    opt.Name=值;
    });
    返回Ok(“Ok”);
    }
    }
    
  • 它将触发
    IOptionsMonitor.OnChange


当您说“对于IOptionsMonitor,它只更改内存中的值…”时,意味着它将作为缓存值使用?。它可以使用多长时间?@D.B当应用程序重新启动或回收时,它将丢失。当你说“对于IOptionsMonitor,它只更改内存中的值…”时,意味着它将作为缓存值使用?。它将可用多长时间?@D.B当应用程序重新启动或回收时,它将丢失。