Configurations in ASP.NET Core

Introduction

In .net framework, appsettings and configuration were much easier. There was a global configuration file(web/app.config) and, within it, there was a section named appsettings that could receive flat key-value pairs of string data.

It was not perhaps the most optimised way as application has to be restarted even after simple change in the configuration file.

What about ASP.NET Core?

ASP.NET Core configuration is key-value pair and it can be read at runtime using a variety of configuration sources:

  • File, such as JSON, XML, INI
  • Environment variables
  • Azure Key Vault
  • Azure App Configuration
  • Command-line arguments
  • Custom providers
  • In-memory collection

Default Configuration

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

CreateDefaultBuilder provides default configuration to the application such as

  • appsettings.json
  • App Secrets
  • Environment Variable
  • Command line arguments

Using Configuration values

Below key-value pair is added to the appsettings.json.

"Greeting": {
        "Information": {
            "City": "Bangalore",
            "Country": "India"
        }
    }

Let’s read the greeting’s key-value pair from appsettings.json using GetValue method

[Route("api/[controller]")]
    [ApiController]
    public class ConfigurationController : ControllerBase
    {
        private readonly IConfiguration configuration;

        public ConfigurationController(IConfiguration configuration)
        {
            this.configuration = configuration;
        }

        [HttpGet]
        public IActionResult Get()
        {
            var city=configuration.GetValue<string>("Greeting:Information:City");
            var country= configuration.GetValue<string>("Greeting:Information:Country");
            var information = $"welcome to {city}-{country}";
            return Ok(information);
        }
    }

The above configuration value is in a hierarchical structure, it can be retrieved using a “:” separated key, starting from root of the hierarchy. In this example, if we want to get value for “city” then the key becomes “Greeting:Information:City”.

Using Configuration GetSection

The GetSection method retrieves a configuration section by its name and is mainly used to access a custom section.

[Route("api/[controller]")]
    [ApiController]
    public class ConfigurationController : ControllerBase
    {
        private readonly IConfiguration configuration;

        public ConfigurationController(IConfiguration configuration)
        {
            this.configuration = configuration;
        }
        [HttpGet]
        public IActionResult Get()
        {
            var information = configuration.GetSection("Greeting:Information");
            var city = information["City"];
            var country = information["Country"];
            var result = $"welcome to {city}-{country}";
            return Ok(result);
        }
    }

“Greeting:Information” is the key used for both City and Country variable. GetSection method is suitable for these kind of examples.

Using Bind Configuration

The downfall of using GetValue method

  • Repetitive Code
  • Fragile naming
  • Can lead to bugs due to hardcoded strings

These above problems can be ruled out by using configuration Bind method.

 public class Greeting
    {
        public string City { get; set; }
        public string Country { get; set; }
    }
 [HttpGet]
        public IActionResult Get()
        {
            var greeting = new Greeting();
            configuration.Bind("Greeting:Information", greeting);
            var result = $"welcome to {greeting.City}-{greeting.Country}";
            return Ok(result);
        }

Here the greeting class is used to remove hardcoded strings.

Using IOption pattern for configuration

The options patterns provide an elegant way to add strongly typed settings to the ASP.NET Core application; moreover, it’s an extension on top of the IServiceCollection interface and it takes advantage of classes to represent a group of related settings. 

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.Configure<Greeting>(Configuration.GetSection("Greeting:Information"));
        }

In order to bind a Greeting class to the configuration you need to configure this in the ConfigureServices method of the Startup class.

[Route("api/[controller]")]
    [ApiController]
    public class ConfigurationController : ControllerBase
    {
        private readonly Greeting greeting;
        public ConfigurationController(IOptions<Greeting> options)
        {
            this.greeting = options.Value;
        }
        [HttpGet]
        public IActionResult Get()
        {
            var result = $"welcome to {greeting.City}-{greeting.Country}";
            return Ok(result);
        }
    }

In constructor, use IOptions injector instead of IConfiguration,

Using IOptionSnapshot for configuration

IoptionSnapshots are also called as “hot loading” of configurations. That is, while running the application, configuration can be changed and reloaded without restarting the application.

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((HostBuilderContext hostBuilderContext, IConfigurationBuilder config) =>
            {
                var env = hostBuilderContext.HostingEnvironment;
                config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).AddJsonFile($"appsettings.{env.EnvironmentName}.json",optional:false,reloadOnChange:true);
                config.AddEnvironmentVariables();
            })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

Add reloadOnChange has to be set to true for the AddJsonFile method and simply change the IOption<Greeting> to IOptionSnapshot<Greeting> in the Controller’s constructor. Rest of the code remains as-is.

 public ConfigurationController(IOptionsSnapshot<Greeting> options)
        {
            this.greeting = options.Value;
        }

I hope you like the article. In case, you find the article as interesting then kindly like and share it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s