1

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!

Angel
  • 21
  • 3
  • Like others have answered below your model is incorrect. Handy hint: If you are using Visual Studio, you can use "Edit->Paste Special->Paste JSON as classes" - it won't be neat, but you can then compare if with your C# model. – Daniel James Bryars Mar 29 '23 at 17:39

3 Answers3

3

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

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • 1
    Turned out that the ConfigurationFile class was at fault too. Removing both Category and ConfigurationFile and binding GetSection("Categories") to the adjusted Categories class directly did the trick. Thank you! – Angel Mar 30 '23 at 08:16
  • @Angel was glad to help!. Yep, missed that, in my test for some reason completely skipped it. – Guru Stron Mar 30 '23 at 09:00
1

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; }
}
Alberto
  • 15,626
  • 9
  • 43
  • 56
0

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>>();
Frenchy
  • 16,386
  • 3
  • 16
  • 39