Work With Configuration In ASP.NET Core

Before going into the new configuration system, let’s discuss in brief how we used to have a configuration system in the earlier versions of .NET applications.

  • We have a Configuration assembly in .NET framework which is used for reading the configuration elements.
  • For any custom elements we used to create ConfigurationElement derived class, and if we have multiple repeated elements we used to have a ConfigurationElementCollection. This way of implementation is like a pester in the earlier versions of .NET because for every custom element, there should be a custom class and then access those custom class elements in the application.
  • And, another thing is web.config file which basically is used as configuration values, and it doesn’t support other forms of files.

ASP.NET Core Configuration System

  • ASP.NET Core/ .NET Core is the restructuring of the existing way of implementation into a set of NuGet Packages. Even though the configuration system is a set of NuGet Packages, the primary package is Microsoft.Extensions.Configuration.
  • The new configuration system is not just the web.config file. It also supports multiple files (JSON, INI etc). Basically Configuration read at runtime.
  • There are several different configuration providers for file formats, like JSON, XML and INI file and it also supports in-memory configuration.
  • It also supports command line and Environment variables.
  • All of these are parts of each individual NuGet Package.

The new configuration system is like a hierarchical element configuration. Let’s move onto the next line to understand better what exactly hierarchical element configuration means.

When we create a new project with ASP.NET Core template, by default, it provides some support for the configuration values.

The project structure looks like below,

ASP.NET core

If you are not aware of this project structure, I recommend you go through the link below before continuing with configuration system in ASP.NET Core project.  

If we look at the startup file the first thing we observe is like ConfigurationBuilder

  1. var builder = new ConfigurationBuilder()  
  2.                 .SetBasePath(env.ContentRootPath)  
  3.                 .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)  
  4.                 .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)  
  5.                 .AddEnvironmentVariables();  
  6. Configuration = builder.Build();  
  • ConfigurationBuilder is one of the primary classes in the new configuration system. Basically It sets up the configuration for the application, it creates the new ConfigurationBuilder class and sets the base path where to look for the configuration provider files and it is adding the JSON file appsettings.json and saying it is an optional which means if the file is not present it will not detonate.
  • It is also providing an environment specific JSON file to override the values for that particular environment like development or production configuration.
  • One important note is that the environment specific file takes the priority here.
  • And also the last line describes that it adds support for environment variables as well.

At the end, it calls the Build(), which returns the IConfiguration root object. The configuration builder follows builder design pattern. Let’s move on to the sample code to understand configuration system in clear.

Lets open appsettings.json file and create some new set of values as shown in the below.

  1. {  
  2.   "Logging": {  
  3.     "IncludeScopes"false,  
  4.     "LogLevel": {  
  5.       "Default""Warning"  
  6.     }  
  7.   },  
  8.   "applicationInfo": {  
  9.     "application": {  
  10.       "files": [  
  11.         {  
  12.           "resourceType""custom",  
  13.           "resourceUrl""https://<websiteAddress>/StorageID/applicationName/resource1"  
  14.         },  
  15.         {  
  16.           "resourceType""pictures",  
  17.           "resourceUrl""https://<websiteAddress>/SID/applicationName/pictures/rs2"  
  18.         }  
  19.       ]  
  20.     },  
  21.     "runmode": {  
  22.       "id""AO839PJ",  
  23.       "framework""dotnetFX45"  
  24.     },  
  25.     "safemode"true  
  26.   }  

This sample json specifies some application information with some resources/files and pictures locations. We need to use this custom configuration values in our WebAPI end point. As we know there is a default controller created by the template, we can access those values from that controller.

In the startup class, there is a configuration root created at the end of the startup (the below line)

  1. public IConfigurationRoot Configuration { get; }  

This is the class that needs to be available everywhere to access those values inside the JSON file. To make this available into the controllers, we have to inject this configuration for each controller. We can add this as a singleton class because we don’t want a separate instance for each controller. Add the below line in ConfigureServices method in startup class.

  1. services.AddSingleton<IConfiguration>(Configuration);  

So, this makes a configuration object available for all the controllers wherever it is referred in the constructor. To understand better let’s add the below code in values controller.

  1. public class ValuesController : Controller  
  2.     {  
  3.         IConfiguration _configuration;  
  5.         public ValuesController(IConfiguration config)  
  6.         {  
  7.             _configuration = config;  
  8.         }  
  10.         // GET api/values  
  11.         [HttpGet]  
  12.         public string[] Get()  
  13.         {  
  14.             List<string> configValues = new List<string>();  
  15.             configValues.Add(_configuration.GetValue<string>("applicationInfo:runmode:framework"));  
  16.             configValues.Add(_configuration.GetValue<string>("applicationInfo:safemode"));  
  17.             configValues.Add(_configuration.GetValue<string>("applicationInfo:files:0:resourceType"));  
  18.             configValues.Add(_configuration.GetValue<string>("applicationInfo:files:1:resourceUrl"));  
  19.             return configValues.ToArray();  
  20.         }  
  22.     }  

Here we added a configuration parameter to the constructor and created a class level property _configuration that can be used as an endpoint. Initialized the property in the constructor and using that configuration object we can access the configuration values. We have a method called GetValue where we can specify the type of element value being retrieved and the key. As we know configuration system supports hierarchical elements we can access the multi level elements as shown above. For demonstration purpose, the values are displayed on the browser. In real time, we will be using this configuration values to perform any business logic/connecting to a server. Once you run the application the output should look like below.

ASP.NET core

This is about reading simple properties from configuration files. Another interesting feature of configuration system is, it supports reading entire section into POCO class. This can be achieved by something called IOptions. Let see the below example to work with IOptions.

To Configure options we should add another NuGet Package called Microsoft.Extensions.Options.ConfigurationExtensions. And also we need to tell the dependency injection system which section of the configuration file need to be used to create a RunMode class. It’s a kind of mapping between class and configuration section. Let's add the below line in ConfigurationServices method in startup class.

  1. services.Configure<RunMode>(Configuration.GetSection("runmode"));  

I have already created a RunMode class for mapping the configuration values. The RunMode class should look like below,

  1. using System.Collections.Generic;  
  2. using System.Linq;  
  3. using System.Threading.Tasks;  
  5. namespace SampleWebApiCoreProject  
  6. {  
  7.     public class RunMode  
  8.     {  
  9.         public string Id { get; set; }  
  10.         public string Framework { get; set; }  
  11.     }  
  12. }  

Now, let's go back to the controller and inject a parameter into the constructor IOptions<RunMode> runModeInstance. So, this option class will provide as a runModeInstance and it (ie IOptions) has a property called Value which holds the actual POCO class. After adding this IOptions to the values controller constructor should looks like below,

  1. IConfiguration _configuration;  
  2. RunMode _runModeInstance;  
  4. public ValuesController(IConfiguration config, IOptions<RunMode> runModeInstance)  
  5. {  
  6.     _configuration = config;  
  7.     _runModeInstance = runModeInstance.Value;  
  8. }  

Once you instantiated the endpoint with Options, we can directly access configuration values as properties to an object as shown below.

  1. [HttpGet]  
  2. public string[] Get()  
  3. {  
  4.    var framework = _runModeInstance.Framework;  
  5. }  

So, this is the new configuration system in ASP.NET Core / .NET Core. For more details about how to work with Console based commandLine and InMemory Collection etc. in configuration system in ASP.NET core, please go through the Microsoft official website. If you are not able to understand those options, please drop a comment or message to me and I will prepare a new article for you with those features like CommandLine, InMemory, Web.Config, and IOptionsSnapshot etc.