zoukankan      html  css  js  c++  java
  • asp.net core 动态更新 appsetting.json方法

    如何将值更新到appsetting.json?

    我正在使用官方文档中IOptions描述的模式.

    当我从中读取值时appsetting.json,这可以正常工作,但是如何更新值并将更改保存回来appsetting.json

    在我的例子中,我有几个字段可以从用户界面编辑(由管理员用户在应用程序中).因此,我正在寻找通过选项访问器更新这些值的理想方法.

    Matze..  32

    在编写此答案时,似乎没有Microsoft.Extensions.Options包提供的组件具有将配置值写回的功能appsettings.json.

    在我的一个ASP.NET Core项目中,我想让用户更改一些应用程序设置 - 这些设置值应该appsettings.json更准确地存储在可选appsettings.custom.json文件中,如果存在,则会添加到配置中.

    像这样...

    public Startup(IHostingEnvironment env)
    {
        IConfigurationBuilder builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile("appsettings.custom.json", optional: true, reloadOnChange: true)
            .AddEnvironmentVariables();
    
        this.Configuration = builder.Build();
    }
    

    我宣布IWritableOptions<T>扩展的接口IOptions<T>; 这样我就可以替代IOptions<T>IWritableOptions<T>每当我想读写设置.

    public interface IWritableOptions<out T> : IOptions<T> where T : class, new()
    {
        void Update(Action<T> applyChanges);
    }
    

    此外,我想出了IOptionsWriter一个组件,旨在用于IWritableOptions<T>更新配置部分.这是我对前面提到的接口的实现......

    class OptionsWriter : IOptionsWriter
    {
        private readonly IHostingEnvironment environment;
        private readonly IConfigurationRoot configuration;
        private readonly string file;
    
        public OptionsWriter(
            IHostingEnvironment environment, 
            IConfigurationRoot configuration, 
            string file)
        {
            this.environment = environment;
            this.configuration = configuration;
            this.file = file;
        }
    
        public void UpdateOptions(Action<JObject> callback, bool reload = true)
        {
            IFileProvider fileProvider = this.environment.ContentRootFileProvider;
            IFileInfo fi = fileProvider.GetFileInfo(this.file);
            JObject config = fileProvider.ReadJsonFileAsObject(fi);
            callback(config);
            using (var stream = File.OpenWrite(fi.PhysicalPath))
            {
                stream.SetLength(0);
                config.WriteTo(stream);
            }
    
            this.configuration.Reload();
        }
    }
    

    由于编写器不知道文件结构,我决定将段处理为JObject对象.访问者尝试查找请求的部分并将其反序列化为实例T,使用当前值(如果未找到),或者仅创建新实例(T如果当前值为)null.然后将此持有者对象传递给调用者,调用者将对其应用更改.比更改的对象转换回JToken将要替换该部分的实例...

    class WritableOptions<T> : IWritableOptions<T> where T : class, new()
    {
        private readonly string sectionName;
        private readonly IOptionsWriter writer;
        private readonly IOptionsMonitor<T> options;
    
        public WritableOptions(
            string sectionName, 
            IOptionsWriter writer, 
            IOptionsMonitor<T> options)
        {
            this.sectionName = sectionName;
            this.writer = writer;
            this.options = options;
        }
    
        public T Value => this.options.CurrentValue;
    
        public void Update(Action<T> applyChanges)
        {
            this.writer.UpdateOptions(opt =>
            {
                JToken section;
                T sectionObject = opt.TryGetValue(this.sectionName, out section) ?
                    JsonConvert.DeserializeObject<T>(section.ToString()) :
                    this.options.CurrentValue ?? new T();
    
                applyChanges(sectionObject);
    
                string json = JsonConvert.SerializeObject(sectionObject);
                opt[this.sectionName] = JObject.Parse(json);
            });
        }
    }
    

    最后,我实现了一个扩展方法,IServicesCollection允许我轻松配置可写选项访问器...

    static class ServicesCollectionExtensions
    {
        public static void ConfigureWritable<T>(
            this IServiceCollection services, 
            IConfigurationRoot configuration, 
            string sectionName, 
            string file) where T : class, new()
        {
            services.Configure<T>(configuration.GetSection(sectionName));
    
            services.AddTransient<IWritableOptions<T>>(provider =>
            {
                var environment = provider.GetService<IHostingEnvironment>();
                var options = provider.GetService<IOptionsMonitor<T>>();
                IOptionsWriter writer = new OptionsWriter(environment, configuration, file);
                return new WritableOptions<T>(sectionName, writer, options);
            });
        }
    }
    

    哪个可以用在ConfigureServices......

    services.ConfigureWritable<CustomizableOptions>(this.Configuration, 
        "MySection", "appsettings.custom.json");
    

    在我的Controller课程中,我可以要求一个IWritableOptions<CustomizableOptions>具有相同特征的实例IOptions<T>,但也允许更改和存储配置值.

    private IWritableOptions<CustomizableOptions> options;
    
    ...
    
    this.options.Update((opt) => {
        opt.SampleOption = "...";
    });
    

    ceferrari..  30

    简化版Matze的答案:

    public interface IWritableOptions<out T> : IOptionsSnapshot<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 string _section;
        private readonly string _file;
    
        public WritableOptions(
            IHostingEnvironment environment,
            IOptionsMonitor<T> options,
            string section,
            string file)
        {
            _environment = environment;
            _options = options;
            _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));
        }
    }
    
    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 environment = provider.GetService<IHostingEnvironment>();
                var options = provider.GetService<IOptionsMonitor<T>>();
                return new WritableOptions<T>(environment, options, section.Key, file);
            });
        }
    }
    

    用法:

    services.ConfigureWritable<MyOptions>(Configuration.GetSection("MySection"));
    

    然后:

    private readonly IWritableOptions<MyOptions> _options;
    
    public MyClass(IWritableOptions<MyOptions> options)
    {
        _options = options;
    }
    

    要将更改保存到文件:

    _options.Update(opt => {
        opt.Field1 = "value1";
        opt.Field2 = "value2";
    });
    

    并且您可以将自定义json文件作为可选参数传递(默认情况下它将使用appsettings.json):

    services.ConfigureWritable<MyOptions>(Configuration.GetSection("MySection"), "appsettings.custom.json");
    
    • 我不太确定“ MyOptions”,但是阅读此内容有助于我弄清楚。https://codingblast.com/asp-net-core-configuration-reloading-binding-injecting/ (2认同)
  • 相关阅读:
    开源Jabber(XMPP) IM服务器介绍
    ejabberd、jabber、jabberd、xmpp辨析
    分布式与集群的区别
    浅谈Javascript事件模拟
    理清javascript的相关概念 DOM和BOM
    js基础学习第一天(关于DOM和BOM)一
    处理机调度和死锁
    C++11 之 " = delete "
    小数的二进制表示
    二进制数的插入
  • 原文地址:https://www.cnblogs.com/tianfengcc/p/12588097.html
Copyright © 2011-2022 走看看