DEV Community

Cover image for Read configuration files in ASP.NET Core
Mirza Leka
Mirza Leka

Posted on

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
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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)
{
   ...
}
Enter fullscreen mode Exit fullscreen mode

Reading simple values

{
  "Name": "Mirza"
}
Enter fullscreen mode Exit fullscreen mode

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

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

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The same applies to other simple types:

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

Reading nested values

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

  "Bosnia": {
    "Capital": "Sarajevo",
    "Founded": 1461
  },
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

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

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"
Enter fullscreen mode Exit fullscreen mode

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

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

This syntax can also be used to retrieve nested values:

var capital = configuration["Europe:Bosnia:Capital"];
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

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; }
}
Enter fullscreen mode Exit fullscreen mode

Then, map it in your class:

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

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;"
  },
Enter fullscreen mode Exit fullscreen mode

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));
Enter fullscreen mode Exit fullscreen mode

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": "you@example.com",
    "PublicKey": "PUBLIC_KEY",
    "PrivateKey": "PRIVATE_KEY"
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

Registering dependencies via the Options Pattern

This is where you map the VapidConfig section from appsettings.json into the previously created model. This is done using the Configure<T>() method on the builder.Services:

// Program.cs

builder.Services.Configure<VapidConfig>(builder.Configuration.GetSection("VapidConfig"));
Enter fullscreen mode Exit fullscreen mode

Using the Options pattern

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
    );
}
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode
var name = configuration["Name"]; // "Batman"
Enter fullscreen mode Exit fullscreen mode

Keep learning. Useful links:

Top comments (0)