[ASP.NET Core] Get values from IConfiguration
Tags: csharp, aspnetcore
Published: 2022-02-20 17:49:08

## Intro
I usually just add string values into config files.
But when I added some other type values, I couldn't get them.

So I try getting values from "appsettings.Development.json" in this time.

### Environments
* .NET ver.6.0.102
* NLog.Web.AspNetCore ver.4.14.0

## Sample Project

#### appsettings.json
```json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}
```
#### appsettings.Development.json
```json
{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "SampleText": "Hello",
  "SampleNumber": 3,
  "SampleBoolean": true,
  "SampleArray": ["Hello", "World"],
  "SampleBook": { "id": 5, "name": "Sample"},
  "SampleBooks": [{ "Id": 6, "Name": "Sample1"},
    { "Id": 7, "Name": "Sample2"}],
  "NullSample": null
}
```

#### Program.cs
```cs
using NLog.Web;

var logger = NLogBuilder.ConfigureNLog("Nlog.config").GetCurrentClassLogger();
try 
{
    var builder = WebApplication.CreateBuilder(args);
    builder.Host.ConfigureLogging(logging =>
    {
        logging.ClearProviders();
        logging.AddConsole();
    })
    .UseNLog();
    builder.Services.AddControllers();
    
    var app = builder.Build();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
    app.Run();
}
catch(Exception ex)
{
    logger.Error(ex, "Stopped program because of exception");
}
finally
{
    NLog.LogManager.Shutdown();
}
```

#### Book.cs
```cs
namespace ConfigSample.Books.Models;

public record Book
{
    public int Id { get; init; }
    public string Name { get; init; } = "";
}
```

#### HomeController.cs
```cs
using ConfigSample.Books.Models;
using Microsoft.AspNetCore.Mvc;

namespace ConfigSample.Controllers;

public class HomeController: Controller
{
    private readonly ILogger<HomeController> logger;
    private readonly IConfiguration config;
    public HomeController(ILogger<HomeController> logger,
        IConfiguration config)
    {
        this.logger = logger;
        this.config = config;
    }
    [Route("")]
    public string Index()
    {
        // get values and log them here.
        
        return "Hello World";
    }
}
```

## Getting primitive type values

In JSON, I can use string, number, boolean, array, object, and null.
Among them, I can get string, number, boolean values with very simple way.

* [JSON](https://www.json.org/json-en.html)
* [JSON - MDN Web Docs Glossary: Definitions of Web-related terms - MDN](https://developer.mozilla.org/en-US/docs/Glossary/JSON)

#### HomeController.cs
```cs
...
    [Route("")]
    public string Index()
    {
        // get values and log them here.
        this.logger.LogDebug(this.config["SampleText"]);
        this.logger.LogDebug(this.config["SampleNumber"]);
        this.logger.LogDebug(this.config["SampleBoolean"]);
        this.logger.LogDebug(this.config["NullSample"]);
        return "Hello World";
    }
...
```

#### Result
```
dbug: ConfigSample.Controllers.HomeController[0]
      Hello
2022-02-21 01:28:32.2159||DEBUG|ConfigSample.Controllers.HomeController|Hello
dbug: ConfigSample.Controllers.HomeController[0]
      3
2022-02-21 01:28:32.2342||DEBUG|ConfigSample.Controllers.HomeController|3
dbug: ConfigSample.Controllers.HomeController[0]
      True
2022-02-21 01:28:32.2342||DEBUG|ConfigSample.Controllers.HomeController|True
dbug: ConfigSample.Controllers.HomeController[0]
2022-02-21 01:28:32.2342||DEBUG|ConfigSample.Controllers.HomeController|

```

### Null values are as same as the values what are not found?
No.

When I set value as null, I wil get empty values from IConfiguration.
But when the key isn't found, I will get null.

#### HomeController.cs
```cs
...
    [Route("")]
    public string Index()
    {
...
        // key:SampleText1 isn't found in appsettings.json and appsettings.Development.json
        var notFound = this.config["SampleText1"];
        this.logger.LogDebug($"NotFound Null?:{(notFound == null)} Empty:{(notFound == "")}");
        var nullValue = this.config["NullSample"];
        this.logger.LogDebug($"NullValue Null?:{(nullValue == null)} Empty:{(nullValue == "")}");
        
        return Json(new Book
        {
            Id = 1,
            Name = "Hello World"
        });
    }
...
```

#### Result
```
dbug: ConfigSample.Controllers.HomeController[0]
      NotFound Null?:True Empty:False
2022-02-21 01:41:24.1251||DEBUG|ConfigSample.Controllers.HomeController|NotFound Null?:True Empty:False
2022-02-21 01:41:24.1459||DEBUG|ConfigSample.Controllers.HomeController|NullValue Null?:False Empty:True
dbug: ConfigSample.Controllers.HomeController[0]
      NullValue Null?:False Empty:True
```

## Get array values
I can't get array values like primitive types.

#### HomeController.cs
```cs
...
    [Route("")]
    public string Index()
    {
...
        // this return null
        this.logger.LogDebug(this.config["SampleArray"]);
        
        return Json(new Book
        {
            Id = 1,
            Name = "Hello World"
        });
    }
...
```

#### Result
```
2022-02-21 02:01:14.6479||DEBUG|ConfigSample.Controllers.HomeController|[null]
dbug: ConfigSample.Controllers.HomeController[0]
      [null]
```

To get the value, I have to use "GetSection".

#### HomeController.cs
```cs
...
    [Route("")]
    public string Index()
    {
...
        var aryList = this.config.GetSection("SampleArray");
        foreach(var ary in aryList.AsEnumerable())
        {        
            this.logger.LogDebug($"Array Key: {ary.Key} Value: {ary.Value}");
        }
        // I also can get value from the index.
        this.logger.LogDebug($"Object {aryList.GetValue(typeof(string), "0")}");
        
        return Json(new Book
        {
            Id = 1,
            Name = "Hello World"
        });
    }
...
```

#### Result
```
dbug: ConfigSample.Controllers.HomeController[0]
      Array Key: SampleArray Value:
2022-02-21 02:14:59.8252||DEBUG|ConfigSample.Controllers.HomeController|Array Key: SampleArray Value:
dbug: ConfigSample.Controllers.HomeController[0]
      Array Key: SampleArray:1 Value: World
2022-02-21 02:14:59.8435||DEBUG|ConfigSample.Controllers.HomeController|Array Key: SampleArray:1 Value: World
2022-02-21 02:14:59.8435||DEBUG|ConfigSample.Controllers.HomeController|Array Key: SampleArray:0 Value: Hello
dbug: ConfigSample.Controllers.HomeController[0]
      Array Key: SampleArray:0 Value: Hello
dbug: ConfigSample.Controllers.HomeController[0]
      Object Hello
2022-02-21 02:14:59.8474||DEBUG|ConfigSample.Controllers.HomeController|Object Hello
```

Or I can bind into variables.

#### HomeController.cs
```cs
...
    [Route("")]
    public string Index()
    {
...
        var stringList = new List<string>();
        this.config.GetSection("SampleArray").Bind(stringList);
        foreach(var ary in stringList)
        {        
            this.logger.LogDebug($"String Value: {ary}");
        }
        
        return Json(new Book
        {
            Id = 1,
            Name = "Hello World"
        });
    }
...
```

#### Result
```
dbug: ConfigSample.Controllers.HomeController[0]
      String Value: Hello
2022-02-21 02:14:59.8474||DEBUG|ConfigSample.Controllers.HomeController|String Value: Hello
dbug: ConfigSample.Controllers.HomeController[0]
      String Value: World
2022-02-21 02:14:59.8474||DEBUG|ConfigSample.Controllers.HomeController|String Value: World
```
## Get object values

I also can get and bind object values.

#### HomeController.cs
```cs
...
    [Route("")]
    public string Index()
    {
...
        var sampleBook = this.config.GetSection("SampleBook").Get<Book>();
        this.logger.LogDebug($"SampleBook Value: {sampleBook}");

        var sampleBooks = new List<Book>();
        this.config.GetSection("SampleBooks").Bind(sampleBooks);
        foreach(var book in sampleBooks)
        {
            this.logger.LogDebug($"SampleBooks Value: {book}");
        }
        
        return Json(new Book
        {
            Id = 1,
            Name = "Hello World"
        });
    }
...
```

### Constructor
One important thing is I have to use empty constructor for binding classes.

When I created a class like below, I could get only null.

#### Book.cs(Before)
```cs
namespace ConfigSample.Books.Models;

public record Book
{
    public int Id { get; init; }
    public string Name { get; init; } = "";
    // DON'T DO THIS
    public Book(int id, string name)
    {
        Id = id;
        Name = name;
    }
}
```

After I remove the constructor, I can bind the values.

#### Book.cs(After)
```cs
namespace ConfigSample.Books.Models;

public record Book
{
    public int Id { get; init; }
    public string Name { get; init; } = "";
}
```

#### Result
```
2022-02-21 02:33:55.8597||DEBUG|ConfigSample.Controllers.HomeController|SampleBook Value: Book { Id = 5, Name = Sample }

dbug: ConfigSample.Controllers.HomeController[0]
      SampleBook Value: Book { Id = 5, Name = Sample }
dbug: ConfigSample.Controllers.HomeController[0]
      SampleBooks Value: Book { Id = 6, Name = Sample1 }
2022-02-21 02:33:55.8768||DEBUG|ConfigSample.Controllers.HomeController|SampleBooks Value: Book { Id = 6, Name = Sample1 }
dbug: ConfigSample.Controllers.HomeController[0]
      SampleBooks Value: Book { Id = 7, Name = Sample2 }
2022-02-21 02:33:55.8768||DEBUG|ConfigSample.Controllers.HomeController|SampleBooks Value: Book { Id = 7, Name = Sample2 }
```

* [Configuration in ASP.NET Core - Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0)
* [Options pattern in ASP.NET Core - Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-6.0&viewFallbackFrom=aspnetcore-2.1)
* [Configuration.GetSection(String) Method - Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/api/system.configuration.configuration.getsection?view=dotnet-plat-ext-6.0)