Configurations In ASP.NET Core

Introduction

 
In .net framework, appsettings and configurations 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 optimized way as an application has to be restarted even after a 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
  1. public class Program  
  2.     {  
  3.         public static void Main(string[] args)  
  4.         {  
  5.             CreateHostBuilder(args).Build().Run();  
  6.         }  
  7.   
  8.         public static IHostBuilder CreateHostBuilder(string[] args) =>  
  9.             Host.CreateDefaultBuilder(args)  
  10.                 .ConfigureWebHostDefaults(webBuilder =>  
  11.                 {  
  12.                     webBuilder.UseStartup<Startup>();  
  13.                 });  
  14.     }  
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.
  1. "Greeting": {  
  2.         "Information": {  
  3.             "City""Bangalore",  
  4.             "Country""India"  
  5.         }  
  6.     }  
Let's read the greeting's key-value pair from appsettings.json using GetValue method
  1. [Route("api/[controller]")]  
  2.     [ApiController]  
  3.     public class ConfigurationController : ControllerBase  
  4.     {  
  5.         private readonly IConfiguration configuration;  
  6.   
  7.         public ConfigurationController(IConfiguration configuration)  
  8.         {  
  9.             this.configuration = configuration;  
  10.         }  
  11.   
  12.         [HttpGet]  
  13.         public IActionResult Get()  
  14.         {  
  15.             var city=configuration.GetValue<string>("Greeting:Information:City");  
  16.             var country= configuration.GetValue<string>("Greeting:Information:Country");  
  17.             var information = $"welcome to {city}-{country}";  
  18.             return Ok(information);  
  19.         }  
  20.     }  
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.
  1. [Route("api/[controller]")]  
  2.     [ApiController]  
  3.     public class ConfigurationController : ControllerBase  
  4.     {  
  5.         private readonly IConfiguration configuration;  
  6.   
  7.         public ConfigurationController(IConfiguration configuration)  
  8.         {  
  9.             this.configuration = configuration;  
  10.         }  
  11.         [HttpGet]  
  12.         public IActionResult Get()  
  13.         {  
  14.             var information = configuration.GetSection("Greeting:Information");  
  15.             var city = information["City"];  
  16.             var country = information["Country"];  
  17.             var result = $"welcome to {city}-{country}";  
  18.             return Ok(result);  
  19.         }  
  20.     }  
"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.
  1. public class Greeting  
  2.     {  
  3.         public string City { getset; }  
  4.         public string Country { getset; }  
  5.     }  
  6.   
  7. [HttpGet]  
  8.         public IActionResult Get()  
  9.         {  
  10.             var greeting = new Greeting();  
  11.             configuration.Bind("Greeting:Information", greeting);  
  12.             var result = $"welcome to {greeting.City}-{greeting.Country}";  
  13.             return Ok(result);  
  14.         }  
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.
  1. public class Startup  
  2.     {  
  3.         public Startup(IConfiguration configuration)  
  4.         {  
  5.             Configuration = configuration;  
  6.         }  
  7.   
  8.         public IConfiguration Configuration { get; }  
  9.   
  10.         // This method gets called by the runtime. Use this method to add services to the container.  
  11.         public void ConfigureServices(IServiceCollection services)  
  12.         {  
  13.             services.AddControllers();  
  14.             services.Configure<Greeting>(Configuration.GetSection("Greeting:Information"));  
  15.         }  
 In order to bind a Greeting class to the configuration you need to configure this in the ConfigureServices method of the Startup class.
  1. [Route("api/[controller]")]  
  2.     [ApiController]  
  3.     public class ConfigurationController : ControllerBase  
  4.     {  
  5.         private readonly Greeting greeting;  
  6.         public ConfigurationController(IOptions<Greeting> options)  
  7.         {  
  8.             this.greeting = options.Value;  
  9.         }  
  10.         [HttpGet]  
  11.         public IActionResult Get()  
  12.         {  
  13.             var result = $"welcome to {greeting.City}-{greeting.Country}";  
  14.             return Ok(result);  
  15.         }  
  16.     }  
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.
  1. public class Program  
  2.     {  
  3.         public static void Main(string[] args)  
  4.         {  
  5.             CreateHostBuilder(args).Build().Run();  
  6.         }  
  7.   
  8.         public static IHostBuilder CreateHostBuilder(string[] args) =>  
  9.             Host.CreateDefaultBuilder(args)  
  10.             .ConfigureAppConfiguration((HostBuilderContext hostBuilderContext, IConfigurationBuilder config) =>  
  11.             {  
  12.                 var env = hostBuilderContext.HostingEnvironment;  
  13.                 config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).AddJsonFile($"appsettings.{env.EnvironmentName}.json",optional:false,reloadOnChange:true);  
  14.                 config.AddEnvironmentVariables();  
  15.             })  
  16.                 .ConfigureWebHostDefaults(webBuilder =>  
  17.                 {  
  18.                     webBuilder.UseStartup<Startup>();  
  19.                 });  
  20.     }  
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. The rest of the code remains as-is.
  1. public ConfigurationController(IOptionsSnapshot<Greeting> options)  
  2.         {  
  3.             this.greeting = options.Value;  
  4.         }  
I hope you like the article. If you find the article interesting then kindly like and share it.