How to extract a list from appsettings.json in .net core

后端 未结 5 1884
耶瑟儿~
耶瑟儿~ 2020-12-24 00:13

I have an appsettings.json file which looks like this:

{
    \"someSetting\": {
        \"subSettings\": [
            \"one\",
            \"two\",
                 


        
相关标签:
5条回答
  • 2020-12-24 00:47

    In .NetCore this is what I did:

    Normal Setup:

    In your appsettings.json create a configuration section for your custom definitions:

        "IDP": [
        {
          "Server": "asdfsd",
          "Authority": "asdfasd",
          "Audience": "asdfadf"
        },
        {
          "Server": "aaaaaa",
          "Authority": "aaaaaa",
          "Audience": "aaaa"
        }
      ]
    

    Create a class to model the objects:

    public class IDP
    {
        public String Server { get; set; }
        public String Authority { get; set; }
        public String Audience { get; set; }
    
    }
    

    in your Startup -> ConfigureServices

    services.Configure<List<IDP>>(Configuration.GetSection("IDP"));
    

    Note: if you need to immediately access your list within your ConfigureServices method you can use...

    var subSettings = Configuration.GetSection("IDP").Get<List<IDP>>();
    

    Then in your controller something like this:

    Public class AccountController: Controller
    {
        private readonly IOptions<List<IDP>> _IDPs;
        public AccountController(IOptions<List<Defined>> IDPs)
        {
            _IDPs = IDPs;
        }
      ...
    }
    

    just as an example I used it elsewhere in the above controller like this:

           _IDPs.Value.ForEach(x => {
                // do something with x
            });
    

    Edge Case

    In the case that you need multiple configs but they can't be in an array and you have no idea how many sub-settings you will have at any one time. Use the following method.

    appsettings.json

    "IDP": {
        "0": {
          "Description": "idp01_test",
          "IDPServer": "https://intapi.somedomain.com/testing/idp01/v1.0",
          "IDPClient": "someapi",
          "Format": "IDP"
        },
        "1": {
          "Description": "idpb2c_test",
          "IDPServer": "https://intapi.somedomain.com/testing/idpb2c",
          "IDPClient": "api1",
          "Format": "IDP"
        },
        "2": {
          "Description": "MyApp",
          "Instance": "https://sts.windows.net/",
          "ClientId": "https://somedomain.com/12345678-5191-1111-bcdf-782d958de2b3",
          "Domain": "somedomain.com",
          "TenantId": "87654321-a10f-499f-9b5f-6de6ef439787",
          "Format": "AzureAD"
        }
      }
    

    Model

    public class IDP
    {
        public String Description { get; set; }
        public String IDPServer { get; set; }
        public String IDPClient { get; set; }
        public String Format { get; set; }
        public String Instance { get; set; }
        public String ClientId { get; set; }
        public String Domain { get; set; }
        public String TenantId { get; set; }
    }
    

    Create Extension for Expando Object

    public static class ExpandObjectExtension
        {
            public static TObject ToObject<TObject>(this IDictionary<string, object> someSource, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
                   where TObject : class, new()
            {
                Contract.Requires(someSource != null);
                TObject targetObject = new TObject();
                Type targetObjectType = typeof(TObject);
    
                // Go through all bound target object type properties...
                foreach (PropertyInfo property in
                            targetObjectType.GetProperties(bindingFlags))
                {
                    // ...and check that both the target type property name and its type matches
                    // its counterpart in the ExpandoObject
                    if (someSource.ContainsKey(property.Name)
                        && property.PropertyType == someSource[property.Name].GetType())
                    {
                        property.SetValue(targetObject, someSource[property.Name]);
                    }
                }
    
                return targetObject;
            }
        }
    

    ConfigureServices

    var subSettings = Configuration.GetSection("IDP").Get<List<ExpandoObject>>();
    
    var idx = 0;
    foreach (var pair in subSettings)
    {
    
        IDP scheme = ((ExpandoObject)pair).ToObject<IDP>();
        if (scheme.Format == "AzureAD")
        {
            // this is why I couldn't use an array, AddProtecedWebApi requires a path to a config section
            var section = $"IDP:{idx.ToString()}";
            services.AddProtectedWebApi(Configuration, section, scheme.Description);
            // ... do more stuff
            
        }
        idx++;
    }
    
    0 讨论(0)
  • 2020-12-24 00:49

    Assuming your appsettings.json looks like this:

    {
      "foo": {
        "bar": [
          "1",
          "2",
          "3"
        ]
      }
    }
    

    You can extract the list items like so:

    Configuration.GetSection("foo:bar").Get<List<string>>()
    
    0 讨论(0)
  • 2020-12-24 00:58
    var settingsSection = config.GetSection["someSettings:subSettings"];
    var subSettings = new List<string>;
    
    foreach (var section in settingsSection.GetChildren())
    {
        subSettings.Add(section.Value);
    }
    

    This should give you the values you need, stored in subSettings

    Apologies for bringing up a semi-old thread. I had difficulty finding an answer as a good amount of methods are deprecated, like Get and GetValue. This should be fine if you only need a simple solution without the configuration binder. :)

    0 讨论(0)
  • 2020-12-24 01:00

    You can use the Configuration binder to get a strong type representation of the configuration sources.

    This is an example from a test that I wrote before, hope it helps:

        [Fact]
        public void BindList()
        {
            var input = new Dictionary<string, string>
            {
                {"StringList:0", "val0"},
                {"StringList:1", "val1"},
                {"StringList:2", "val2"},
                {"StringList:x", "valx"}
            };
    
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddInMemoryCollection(input);
            var config = configurationBuilder.Build();
    
            var list = new List<string>();
            config.GetSection("StringList").Bind(list);
    
            Assert.Equal(4, list.Count);
    
            Assert.Equal("val0", list[0]);
            Assert.Equal("val1", list[1]);
            Assert.Equal("val2", list[2]);
            Assert.Equal("valx", list[3]);
        }
    

    The important part is the call to Bind.

    The test and more examples are on GitHub

    0 讨论(0)
  • 2020-12-24 01:00

    In my case configuration

     services.Configure<List<ApiKey>>(Configuration.GetSection("ApiKeysList"));
    

    wasn't loaded because the properties were read-only and there were no default constructor

     **//not working** 
      public class ApiKey : IApiKey
        {
            public ApiKey(string key, string owner)
            {
                Key = key;
                OwnerName = owner;
            }
            public string Key { get;  }
            public string OwnerName { get;}
        } 
    

    //Working

        public class ApiKey : IApiKey
        {
            public ApiKey(){}//Added default constructor
            public ApiKey(string key, string owner)
            {
                Key = key;
                OwnerName = owner;
            }
            public string Key { get; set; }        //Added set property
            public string OwnerName { get; set; }  //Added set property
        } 
    
    0 讨论(0)
提交回复
热议问题