asp.net-core - 手动触发 IOptionsMonitor<>.OnChange
问题描述
在 ASP.NET Core 2.1 中,我使用 IOptionsMonitor<> 并对其进行设置,以便在更改 appSettings.json 文件时成功获取事件。所以这是有效的。
我现在要做的是通过代码手动更改我的选项中的一些值,并让它触发我所有的监视器。这可能吗?
解决方案
因为IOptionsMonitor<Locations>
,它只是改变了内存中的值,并没有保存回appsettings.json
。对于解决方法,您需要实现自己的方法将更改保存回appsettings.json
.
定义
IWritableOptions
继承自IOptions
public interface IWritableOptions<out T> : IOptions<T> where T : class, new() { void Update(Action<T> applyChanges); }
实现你自己的
WritableOptions
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<T>
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); }); } }
注册
Startup
services.ConfigureWritable<Locations>(Configuration.GetSection("Locations"));
利用
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"); } }
它会发射
IOptionsMonitor<>.OnChange
推荐阅读
- mysql - 从许多不同的表中选择并加入
- java - 将令牌添加到 AWS api 网关的 http
- python - 过滤列表中与每行 pandas 的条件匹配的第一个元素
- javascript - 使用 Emotion 样式 + material-ui + typescript 的类型实例化太深并且可能是无限的
- java - Java 异常设计:必须被捕获或声明被抛出 => 太多的代码影响
- python-3.x - 如何使用机器人框架 selenium2Library 单击框架内的链接?
- c# - 如何在 asp.net 中正确地将查询转换为 DateTime?
- awk - awk 中的 int() 函数会更改参数,即使这已经是整数
- vuejs2 - 在 vuejs 中选择选项时如何获取 optgroup 标签?
- powerbi - 如何更改已发布 Power BI 应用的所有者