IOptions returns null despite GetSection working

156 views Asked by At

I'm currently trying to read appsettings.json values into a variable. GetSection() successfully reads the values but once I try to actually use said values for a variable it only ever returns null. None of the solutions I found worked.

Json file

{
  "Categories": {
    "Over29EUR": [
      {
        "Status": "DO1",
        "CaseMemo": "Over 29",
        "CopyOldData": false,
        "OverwriteData": false,
        "DeleteOldEvent": true,
        "NextEvent": "next",
        "CaseMemoManualCheck": "",
        "Team": "",
        "NewStatus": "new"
      },
      {
        "Status": "DO2",
        "CaseMemo": "Over 29",
        "CopyOldData": false,
        "OverwriteData": false,
        "DeleteOldEvent": true,
        "NextEvent": "next",
        "CaseMemoManualCheck": "",
        "Team": "",
        "NewStatus": "new"
      },
      {
        "Status": "DO3",
        "CaseMemo": "Over 29",
        "CopyOldData": false,
        "OverwriteData": false,
        "DeleteOldEvent": true,
        "NextEvent": "next",
        "CaseMemoManualCheck": "",
        "Team": "",
        "NewStatus": "new"
      }
    ]
  }
}

Program.cs

    private static IConfiguration config;

    static void Main(string[] args)
    {
        config = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("Resources\\appsettings.json", optional: false)
            .Build();


        var serviceProvider = new ServiceCollection()    
            .Configure<ConfigurationFile>(config.GetSection("Categories"))
            .AddSingleton<IConfiguration>(Program.config)
            .AddSingleton<IOrchestrator, CaseOrchestrator>()
            .AddOptions()
            .BuildServiceProvider();

        var orchestrator = serviceProvider.GetRequiredService<IOrchestrator>();

        orchestrator.Execute();

    }

Classes

    public class ConfigurationFile
    {
        public Categories Categories { get; set; }
    }
///////////////////////////////////////////////////////////
    public class Categories
    {
       public Category Over29EUR { get; set; }
       public Category Under29EUR { get; set; }
    }
///////////////////////////////////////////////////////////
    public class Category
    {
        public List<ZMRCase> ZMRCases { get; set; }
    }
///////////////////////////////////////////////////////////
    public class ZMRCase
    {
        public string Status { get; set; }
        public string CaseMemo { get; set; }
        public bool? CopyOldData { get; set; }
        public bool? OverwriteData { get; set; }
        public bool? DeleteOldEvent { get; set; }
        public string NextEvent { get; set; }
        public string CaseMemoManualCheck { get; set; }
        public string Team { get; set; }
        public string NewStatus { get; set; }
    }

Orchestrator (where I'm trying to get the value)

    internal class CaseOrchestrator : IOrchestrator
    {
        private readonly ConfigurationFile _configuration;

        public CaseOrchestrator(IOptions<ConfigurationFile> configuration)
        {
            _configuration = configuration.Value;
        }

        public void Execute()
        {
            var x = _configuration;
        }
    }

Thanks!

3

There are 3 answers

2
Guru Stron On BEST ANSWER

Fix the Categories model:

public class Categories
{
    public List<ZMRCase> Over29EUR { get; set; }
    public List<ZMRCase> Under29EUR { get; set; }
}

Also if you are parsing the concrete Categories section - then you need to omit ConfigurationFile too - Configure<Categories>(config.GetSection("Categories"))

It directly contains 2 collections of ZMRCase without intermediate Category's

0
Alberto On

Because that is not the correct class model.

The correct one should be something like:

public class ConfigurationFile
{
    public Categories Categories { get; set; }
}

public class Categories
{
    public List<ZMRCase> Over29EUR { get; set; }
    public List<ZMRCase> Under29EUR { get; set; }
}

public class ZMRCase
{
    public string Status { get; set; }
    public string CaseMemo { get; set; }
    public bool CopyOldData { get; set; }
    public bool OverwriteData { get; set; }
    public bool DeleteOldEvent { get; set; }
    public string NextEvent { get; set; }
    public string CaseMemoManualCheck { get; set; }
    public string Team { get; set; }
    public string NewStatus { get; set; }
}
0
Frenchy On

if you add package Microsoft.Extensions.Configuration.Binder, you could simplify the use class .NET.

just do that:

        var builder = new ConfigurationBuilder().SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                                                .AddJsonFile("appsettings.json");

        config = builder.Build();

        var cat1 = config.GetSection("Categories")
                         .GetSection("Over29EUR")
                         .Get<List<ZMRCase>>();
        var cat2 = config.GetSection("Categories")
                         .GetSection("Under29EUR")
                         .Get<List<ZMRCase>>();

and you could loop over cat1 and cat2 very easily

another way to write:

        var cat1 = config.GetSection("Categories:Over29EUR")
                         .Get<List<ZMRCase>>();