aspnet / Configuration

[Archived] Interfaces and providers for accessing configuration files. Project moved to https://github.com/aspnet/Extensions

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Binding/rebinding JSON array/lists/collections upon change/reload yields duplicate and unexpected results

rwencel opened this issue · comments

Using version 2.0.2, and a config with 2 JSON file sources (appsettings.global.json and appsettings.local.json, where the local settings supersede the global settings), trying to bind a List property gives some duplicate and unexpected results when initially binding and when re-binding on change. Here are some examples:

  1. appsettings.global.json StringList contains [ "1", "2" ] and appsetings.local.json contains [ "3" ]
    Result: At line 42, StringList is bound with the values [ "3", "2" ] upon initial binding
    Expected: StringList is bound with [ "3" ]

  2. appsetings.local.json StringList is changed to [ "3", "4" ]
    Result: At line 68, StringList is bound with values [ "3", "2", "3", "4" ]
    Expected: StringList is bound with [ "3", "4" ]
    Caveat: This problem only happens if you re-bind to the already existing MyConfig instance, as is done in the code, though I think this should be supported, since it works for primitive types, and it allows you to bind to an instance whose reference may already be held by other code.

I couldn't find any doc to indicate if this was by design or not, but I'm hoping someone can shed some light.

Thanks!

using System.Collections.Generic;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;

namespace WebApplication1
{
    public class MyConfig
    {
        public List<string> StringList { get; set; }
    }

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; set; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public MyConfig MyConfig { get; set; } = new MyConfig();

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.global.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.local.json", optional: false, reloadOnChange: true);

            Configuration = builder.Build();

            Configuration.Bind(MyConfig);

            ChangeToken.OnChange(() => Configuration.GetReloadToken(), OnChange);

            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }

        private void OnChange()
        {
            Configuration.Bind(MyConfig);
        }
    }
}

Yeah this is by design at this point, the arrays are converted into indexed key value pairs that look something like array indicies, so that's why you are seeing that kind of behavior.