Home > database >  How can I populated an IEnumerable<MyType>() on an object via configuration?
How can I populated an IEnumerable<MyType>() on an object via configuration?

Time:11-27

I'm trying to populate the following object using the Option pattern:

public class MyParentPolicyOptions
{
    public IEnumerable<SomePolicySettings> SomePolicySettings { get; set; }
}

My config json looks like this:

{
  "MyParentPolicy": {
     "SomePolicies": [
     {
       "Name": "Default",
       "SomeSetting": 3,
       "IsHappy": false
     },
     {
       "Name": "Custom",
       "SomeSetting": 5,
       "IsHappy": true
     }
  ]
}

For the configuration I do something like this:

serviceConfigurationDefinition.Optional("MyParentPolicy", Validators.MyParentPolicyOptions());

At the point of building the configuration builder I can see it has my properties as expected in the following pattern:

{[MyParentPolicy:SomePolicies:0:Name, Default}]
{[MyParentPolicy:SomePolicies:0:SomeSetting, 3}]
{[MyParentPolicy:SomePolicies:0:IsHappy, false}]

However, after applying this configuration root to the ServiceConfigurationDefinition my actual MyParentPolicyOptions.SomePolicySettings is still null. It seems to work for other strongly typed objects but I can't get it to work for Lists / IEnumerables / arrays etc.

Just to add, I've just tried this with Dictionary<int, SomePolicySetting> in the hope that the automatic indexing would mean this was actually a dictionary type, but didn't work.

CodePudding user response:

I don't know for the serviceConfigurationDefinition.Optional() method you use. In general I do it this way. You're right IEnumerable is working. The issue is somewhere else in your code. The following example is working.

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices( (context,services) =>
    {
        services.AddOptions();
        services.Configure<MyParentPolicy>(context.Configuration.GetSection("MyParentPolicy"));
        services.AddHostedService<Worker>();
    })
   .Build();
await host.RunAsync();

    public class MyParentPolicy
    {
        public IEnumerable<SomePolicySettings> SomePolicies { get; set; }
    }

    public class SomePolicySettings
    {
        public string Name { get; set; }
        public string SomeSetting { get; set; }
        public bool IsHappy { get; set; }  
    }

and appsettings.json:

{
  "MyParentPolicy": {
    "SomePolicies": [
      {
        "Name": "Default",
        "SomeSetting": 3,
        "IsHappy": false
      },
      {
        "Name": "Custom",
        "SomeSetting": 5,
        "IsHappy": true
      }
    ]
  }
}

And finally retrieve the options with IOptionsMonitor<MyParentPolicy> for example:

        public Worker(ILogger<Worker> logger, IOptionsMonitor<MyParentPolicy> options)
        {
            _logger = logger;
            _parentPolicyOptions = options.CurrentValue;
        }

CodePudding user response:

The easiest way is to get it from startup configuration

List<SomePolicySettings> settings=  configuration.GetSection("MyParentPolicy")
.Get<MyParentPolicy>().SomePolicies.ToList();

if you want to use it everywhere inside of your app , you can create a service

startup

services.Configure<MyParentPolicy>(configuration.GetSection("MyParentPolicy"));
services.AddSingleton<SomePolicySettingsService>();

service class

public class SomePolicySettingsService
{
    private readonly  List<SomePolicySettings> _somePolicySettings;

    public SomePolicySettingsService(IOptions<MyParentPolicy> myParentPolicy)
    {
         _somePolicySettings  = myParentPolicy.Value.SomePolicies;
    }
    
    public SomePolicySettings GetDefaultPolicySettings()
    {
        return _somePolicySettings.FirstOrDefault(i=>i.Name=="Default");
    }
    public SomePolicySettings GetCustomPolicySettings()
    {
        return _somePolicySettings.FirstOrDefault(i => i.Name == "Custom");
    }
}

or instead of creating and injecting service, you can just inject " IOptions myParentPolicy" in the constructor everywhere you need.

  • Related