4

I have the following appSettings.json file:

  "SundrySettings": {

    "CookieName": "Cookie",

    "AccessGroup": "Software Development",

    "Terminals" :  {
      "Raucherplatz" : "tablet1.local",
      "Service" :      "tablet2.local",  
      "Technik" :      "tablet3.local",  
      "Technik" :      "tablet4.local",  
      "Container" :    "tablet5.local"
    }
  }
}

That I would like to load into the following structure:


    public class Terminal
    {
        public string Name;
        public string Description;
    }

    public class SundryOptions
    {
        public string CookieName { get; set; } = "dummy";
        public string HRAccessGroup { get; set; } = "dummy";
        public List<Terminal> Terminals;
    }

that I would try to load using the following commands:

ServiceProvider sp = services.BuildServiceProvider();
SundryOptions sundryOptions = sp.GetService<IOptions<SundryOptions>>().Value;

The problem I have is that using Property Initialisers never sets the Terminals List correctly. I do need a list (and not a Dictionary) as the enties could be double i.e. Technik in my example.

I am assuming that I have some error in the Class -> I would be happy for any pointers.

TanvirArjel
  • 30,049
  • 14
  • 78
  • 114
Ursus Schneider
  • 447
  • 1
  • 6
  • 22
  • 3
    Don't use a List. What you posted there is a *dictionary*, typically represented as an object. It's not a list. You *can't* parse it as a list – Panagiotis Kanavos Feb 14 '19 at 14:11
  • I did try sundryOptions.Terminals = Configuration.GetSection("SundrySettings:Terminals").Get>(); in ConfigureServices but that did not work unfortunately – Ursus Schneider Feb 14 '19 at 14:18
  • @PanagiotisKanavos I did try a dictionary as well but still get null for the value of Terminals – Ursus Schneider Feb 14 '19 at 14:19
  • Using which class? The `Terminal` class you posted doesn't match the `Terminal` in the json file. `Technik` is a *setting*, not some name in a name/value pair. The path to that setting is `SundrySettings::Terminals::Service` and its value is `tablet2.local`. I suspect you're trying to use the Configuration subsystem like a database? – Panagiotis Kanavos Feb 14 '19 at 14:29
  • That means `Technik` will throw too, because it's not unique. That's how the Configuration system works - each setting has a specific path and a value. Those settings can be mapped to strongly-typed objects. If the objects match the settings, this is trivial. If not, you'll have to write code to map one to the other – Panagiotis Kanavos Feb 14 '19 at 14:32
  • You may want to look at this question [link](https://stackoverflow.com/questions/42846296/how-to-load-appsetting-json-section-into-dictionary-in-net-core). – BigMuzzy Feb 14 '19 at 16:11
  • @UrsusSchneider You marked the copied answer as correct answer. Great! Thank you. When the both answer become similar then you should check the edit history of the answer. – TanvirArjel Feb 15 '19 at 09:10

3 Answers3

8

Do as follows:

var cookieName = Configuration.GetSection("SundrySettings:CookieName").Value;
var accessGroup = Configuration.GetSection("SundrySettings:AccessGroup").Value;
var terminals = Configuration.GetSection("SundrySettings:Terminals").GetChildren();

List<Terminal>  terminalList = new List<Terminal>();

foreach (var keyValuePair in terminals)
{
     Terminal termial = new Terminal()
     {
          Name = keyValuePair.Key,
          Description = keyValuePair.Value
     };

     terminalList.Add(termial);
}

SundryOptions sundryOption = new SundryOptions()
{
            CookieName = cookieName,
            HRAccessGroup = accessGroup,
            Terminals = terminalList
};

I have checked with the exact configuration you provided and it works perfectly.

TanvirArjel
  • 30,049
  • 14
  • 78
  • 114
5

Implement processing of configuration as following somewhere approporiate like this:

var cookieName = 
Configuration.GetSection("SundrySettings:CookieName").Value;
var accessGroup = Configuration.GetSection("SundrySettings:AccessGroup").Value;

var terminals = new List<Terminal>()

var terminalSections = this.Configuration.GetSection("Terminals").GetChildren();
foreach (var item in terminalSections)
{
    terminals.Add(new Terminal 
    {
           // perform type mapping here 
    });
}

SundryOptions sundryOption = new SundryOptions()
{
        CookieName = cookieName,
        HRAccessGroup = accessGroup,
        Terminals = terminalList
};

Of course there could be shorter version, but you can start from here.

Kristóf Tóth
  • 791
  • 4
  • 19
  • 2
    Brother fully copied my answer :) Okay! no problem. :) – TanvirArjel Feb 14 '19 at 15:58
  • 1
    Nope mate. I answered first you just added the boilerplate to that... :) then I filled the boilerplate in. But if you have hard feelings just vote it down. – Kristóf Tóth Feb 14 '19 at 18:41
  • 1
    No no! I don't feel envy to anybody so that I shall down vote. It's ok. Best of luck. By the way there is edit history your first answer was wrong too. Ok. Keep going. – TanvirArjel Feb 14 '19 at 18:44
1

If Terminals is a list, in your appSettings, it should be an array, not an object.

  "Terminals" :  [
  "Raucherplatz" : "tablet1.local",
  "Service" :      "tablet2.local",  
  "Technik" :      "tablet3.local",  
  "Technik" :      "tablet4.local",  
  "Container" :    "tablet5.local"
]
Zoe
  • 856
  • 1
  • 9
  • 22