Dev.to WebDev 🛠 Dev 👁 0 📖 4 min read

Read configuration files in ASP.NET Core

This article will teach you how to read data from the appsettings.json file in ASP .NET Core. Why do we need configuration files? The configuration files separate an application's settings from its core sourc

Read configuration files in ASP.NET Core

This article will teach you how to read data from the appsettings.json file in ASP .NET Core.

Why do we need configuration files?

The configuration files separate an application's settings from its core source code. This is where you store:

  • Database connection string
  • Routes of HTTP clients you're calling
  • Client credentials
  • Logging configuration, etc.

Consider the following data in the appsettings.json file:

asp-appsettings

{
  "Name": "Mirza",
  "AgeOfBirth": 1994,
  "IsAwesome": true,
  "Hobbies": ["ASP .NET", "Node.js", "Call of Duty"],
  "Europe": {
    "Bosnia": {
      "Capital": "Sarajevo",
      "Founded": 1461
    }
  }
}

How to read these values in the controller or service class?

IConfiguration

The IConfiguration interface represents a set of key/value application configuration properties. It lives in the Microsoft.Extensions.Configuration namespace and is used to read the configuration from appsettings.json or environment files.

It can be injected into any constructor:

public class MyService(IConfiguration configuration)
{
   ...
}

Reading simple values

{
  "Name": "Mirza"
}

To read the property from settings, use the GetValue<T>() method on the configuration object:

var name = configuration.GetValue<string>("Name"); // Mirza

The method requires the correct property name in appsettings.json. If you pass something that doesn't exist, it'll return null:

var name = configuration.GetValue<string>("ABC"); // null

That said, the configuration isn't case sensitive.

var name1 = configuration.GetValue<string>("Name"); // Mirza
var name2 = configuration.GetValue<string>("name"); // Mirza
var name3 = configuration.GetValue<string>("NAME"); // Mirza
var name4 = configuration.GetValue<string>("nAME"); // Mirza

The same applies to other simple types:

var born = configuration.GetValue<int>("AgeOfBirth"); // 1994
var isAwesome = configuration.GetValue<bool>("IsAwesome"); // true

Reading nested values

Given the settings object, how to the values of nested properties?

  "Bosnia": {
    "Capital": "Sarajevo",
    "Founded": 1461
  },

Use the parent property name, followed by the separator :, then the child property:

var capital = configuration.GetValue<string>("Bosnia:Capital"); // "Sarajevo"
var founded = configuration.GetValue<int>("Bosnia:Founded"); // 1461

This works even with deeply nested objects, e.g:

  "Europe": {
    "Bosnia": {
      "Capital": "Sarajevo",
      "Founded": 1461
    }
  },
var capital = configuration.GetValue<string>("Europe:Bosnia:Capital"); // Sarajevo

Alternative syntax

The shorthand syntax configuration["property"] allows you to read simple values as a string.

var name = configuration["Name"]; // "Mirza"
var bornAsString = configuration["AgeOfBirth"]; // "1994"
var isAwesomeAsString = configuration["IsAwesome"]; // "True"

That said, you need to convert a string to another primitive type:

var born = int.Parse(bornAsString); // 1994
var isAwesome = bool.Parse(isAwesomeAsString); // true

This syntax can also be used to retrieve nested values:

var capital = configuration["Europe:Bosnia:Capital"];

Reading arrays

For more complex types, we need to use the configuration.GetSection("object") method. This method takes the name of the object from appsettings, then calls Get<T>() that maps the object into the appropriate T type:

var hobbies = configuration.GetSection("Hobbies").Get<string[]>();
// ["ASP .NET", "Node.js", "Call of Duty"]

Reading objects

Likewise, use the GetSection() to extract whole objects.

Start by creating a model class:

public class Europe
{
    public Country Bosnia { get; set; }
}

public class Country
{
    public string Capital { get; set; }
}

Then, map it in your class:

var section = configuration.GetSection("Europe").Get<Europe>();
// Europe { Bosnia = Country { Capital = "Sarajevo" } }

Reading DB connection

It's a common practice to keep the database connection string in the appsettings.json file:

  "ConnectionStrings": {
    "GamesDB": "Server=<SERVER_NAME>;Database=<DATABASE_NAME>;Integrated Security=True;TrustServerCertificate=True;"
  },

Although the previously mentioned approach would still work, the IConfiguration interface exposes a special method: configuration.GetConnectionString("...").

Here I'm using the builder.Configuration (which uses IConfiguration) to read the connection string in the Program.cs file, then inject it in the DB Context:

// 👇
var connectionString = builder.Configuration.GetConnectionString("GamesDB");

builder.Services.AddDbContext<GamesContext>(options => 
    options.UseSqlServer(connectionString));

IOptions

The IOptions<T> binds specific configuration sections to strongly typed C# classes. It's used to extract specific sections (objects) and inject them into service methods.

Say you want to extract just the VapidConfig from the following file:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "VapidConfig": {
    "Email": "[email protected]",
    "PublicKey": "PUBLIC_KEY",
    "PrivateKey": "PRIVATE_KEY"
  }
}

Instead of pulling the entire thing via IConfiguration, you can focus on your object using IOptions.

public class VapidConfig
{
    public string Email { get; init; } = string.Empty;
    public string PublicKey { get; init; } = string.Empty;
    public string PrivateKey { get; init; } = string.Empty;
}

Registering dependencies

This is where you map the VapidConfig section from appsettings.json into the previously created model:

// Program.cs

builder.Services.Configure<VapidConfig>(builder.Configuration.GetSection("VapidConfig"));

Using options in classes

Just inject the model into the constructor and wrap it with IOptions<>:

public class YourService(IOptions<VapidConfig> config)
{

    private readonly VapidDetails _vapidDetails = new(
        config.Value.Email,
        config.Value.PublicKey,
        config.Value.PrivateKey
    );
}

The primary difference is the config encapsulation. The user working with IOptions<T> only has access to values for the selected object, rather than the entire configuration file.

Order of precedence

ASP. NET Core projects use multiple configuration files for each environment. Out of the box, you get the appsettings.json (default and production) and appsettings.Development.json (for development).

Itwo-appsettins-files

If two files share the same properties with different values and you're running the app locally, then everything in the development file will override the default appsettings file:

// appsettings.Development.json
{
  "Name": "Batman"
}
var name = configuration["Name"]; // "Batman"

Keep learning. Useful links:

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.