Manually trigger IOptionsMonitor<>.OnChange

前端 未结 1 591
悲&欢浪女
悲&欢浪女 2021-01-26 17:27

In ASP.NET Core 2.1, I use IOptionsMonitor<> and have it set up so I can successfully get events for when I change the appSettings.json file. So this is working.

Wha

1条回答
  •  迷失自我
    2021-01-26 17:33

    For IOptionsMonitor, it only changes the value in memory and did not save back to appsettings.json. For a workaround, you will need to implement your own method to save the changes back to appsettings.json.

    • define IWritableOptions which inherits from IOptions

      public interface IWritableOptions : IOptions where T : class, new()
      {
           void Update(Action applyChanges);
      }
      
    • implement your own WritableOptions

      public class WritableOptions : IWritableOptions where T : class, new()
      {
      private readonly IHostingEnvironment _environment;
      private readonly IOptionsMonitor _options;
      private readonly IConfigurationRoot _configuration;
      private readonly string _section;
      private readonly string _file;
      
      public WritableOptions(
          IHostingEnvironment environment,
          IOptionsMonitor 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 applyChanges)
      {
          var fileProvider = _environment.ContentRootFileProvider;
          var fileInfo = fileProvider.GetFileInfo(_file);
          var physicalPath = fileInfo.PhysicalPath;
      
          var jObject = JsonConvert.DeserializeObject(File.ReadAllText(physicalPath));
          var sectionObject = jObject.TryGetValue(_section, out JToken section) ?
              JsonConvert.DeserializeObject(section.ToString()) : (Value ?? new T());
      
          applyChanges(sectionObject);
      
          jObject[_section] = JObject.Parse(JsonConvert.SerializeObject(sectionObject));
          File.WriteAllText(physicalPath, JsonConvert.SerializeObject(jObject, Formatting.Indented));
          _configuration.Reload();
      }
      }
      
    • Configure IWritableOptions

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

              services.ConfigureWritable(Configuration.GetSection("Locations"));
      
    • Use

      public class OptionsController : Controller
      {
      private readonly IWritableOptions _writableLocations;
      public OptionsController(IWritableOptions writableLocations)
      {
          _writableLocations = writableLocations;
      }
      
      public IActionResult Change(string value)
      {
          _writableLocations.Update(opt => {
              opt.Name = value;
          });
          return Ok("OK");
      }
      }
      
    • It will fire the IOptionsMonitor<>.OnChange

    0 讨论(0)
提交回复
热议问题