THE CONFIGURATION IN ASP.NET CORE MVC

ACCESS CONFIGURATION VALUES WITH THE ICONFIGURATION SERVICE

NET COREConfiguration is a service that will allow us to keep the application’s operating parameters out of the C# code. We will keep them in a JSON file without being forced to recompile the application after a change. That way if we sold the application to a customer they could change the configuration without knowing the inner workings. We create an appsettings.json file, the application is already set up to read values from this file, of course if it is present. Here is the code for getting the ConnectionString to the database. Note how the IConfiguration service was configured in the constructor.

ConnectioString

This is the JSON file.

appsettings.json

If the C value is a string we can use the last part given in the slide.

IConfiguration

USE A STRONGLY TYPED CONFIGURATION WITH THE IOPTIONSMONITOR SERVICE

We saw that to get a connectionString we had to provide parameters of type string in GetSection(…) and GetValue<T>(…). Now we have said it several times when we are dealing with strings we can make typing errors. Let us see how to access the appsettings.json file in a strongly typed manner. We create a new class in the Options folder ConnectionStringsOptions.cs. Now let’s go and register this class in the Startup.cs file. Here is a summary slide.

IOptionsMonitor

Let’s look at the code.

Codice

Let us now see how it is possible to read nested values into appsettings.json always in a strongly typed manner.

Valori annidati

See the class.

CoursesOption

This is the implementation of IOptionsMonitor<T>.

Annidamento

CONFIGURATION SOURCES

Configuration values are not all the same because some have different sensitivity requirements. For example, the number of courses per page is not sensitive information, whereas a ConnectionString to SQLServer might contain sensitive information, such as the User Name, password, and ip address of the server. To avoid disclosing this information ASP.NET Core provides us with several sources of configuration.

Fonti di configurazione

The lowest priority source can be overwritten by a higher priority source. If I want to redefine the PerPage value in appsettings.development.json and write the value 20 this will override the value 10 set in appsettings.json because the priority of the configuration source is higher.

OTHER SOURCES OF CONFIGURATION

We see user secrets being kept away from the project. For example, if my colleague and I need to work with different ConnectionStrings as long as we are in development, we can use this configuration source.

User secrets

In the figure, the parts highlighted in red represent the key and value.

User Secrets

Let’s look at the environment variables.

Variabili di ambiente

The last type are command-line parameters, which cannot be hot updated as user secrets and environment variables but by rebooting the machine.

Riga di comando

THE CONFIGURATION SERVICE

Most applications are flexible enough to admit a configuration. For example, the database connection string or the number of courses to be displayed in the list are configuration values that we should keep in a source outside the application, such as a text file. In this way, our developer will be able to freely modify these values as needed, without having to ask us developers to make changes to the C# code or recompile the application.

ASP.NET Core can make use of various sources of configuration external to the application, such as the appsettings.json file, in which we can enter configuration values organized over several nested sections.

In this example, the ConnectionStrings section contains the Default key which has been assigned the value Data Source=Data/MyCourse.db representing a database connection string.

  1. {
  2. “ConnectionStrings”: {
  3. “Default”: “Data Source=Data/MyCourse.db”
  4. }
  5. }

To read the value from the application, we receive the IConfiguration service from the constructor of any component, including the Startup class. In the following example we read the value from our SqliteDatabaseAccessor infrastructure service.

  1. public class SqliteDatabaseAccessor : IDatabaseAccessor.
  2. {
  3. private readonly IConfiguration configuration;
  4. //Receive service from the manufacturer
  5. public SqliteDatabaseAccessor(IConfiguration configuration).
  6. {
  7. //Conserve the service reference on a private field…
  8. this.configuration = configuration;
  9. }
  10. public async Task QueryAsync(FormattableString formattableQuery)
  11. {
  12. //…and from here we read the value of the “Default” key of the “ConnectionStrings” section
  13. string connectionString = configuration.GetValue(“ConnectionStrings:Default”);
  14. //Or, since it is a value of type string we could write more briefly
  15. //string connectionString = configuration[“ConnectionStrings:Default”];
  16. //Or again, since the value is in the “ConnectionStrings” section:
  17. //string connectionString = configuration.GetConnectionString(“Default”);
  18. //TODO: Here we use connectionString to connect to the database.
  19. }
  20. }

THE IOPTIONSMONITOR<T> SERVICE

As we saw in this example, to the IConfiguration service we need to provide the path to the configuration key, such as ConnectionStrings:Default, where the character : was used as a name separator.

This technique can lend itself to typing errors that we would only discover at runtime, and therefore, to make us more productive, ASP.NET Core also offers another service called IOptionsMonitor<T> which allows us to access configuration values in a strongly typed manner, so that any errors are reported at compile time.

Let us therefore rewrite the previous example as follows:

  1. public class SqliteDatabaseAccessor : IDatabaseAccessor.
  2. {
  3. private readonly IOptionsMonitor<ConnectionStringsOptions> options;
  4. //Receive service from the manufacturer
  5. public SqliteDatabaseAccessor(IOptionsMonitor<ConnectionStringsOptions> options)
  6. {
  7. //Conserve the service reference on a private field…
  8. this.options = options;
  9. }
  10. public async Task QueryAsync(FormattableString formattableQuery)
  11. {
  12. //…and from here we read the Default property of the object of type ConnectionStringsOptions
  13. string connectionString = options.CurrentValue.Default;
  14. //TODO: Here we use connectionString to connect to the database.
  15. }
  16. }

In the example we have just seen, ConnectionStringsOptions is a class that we have to create and that we can call as we wish. It is important that it contain properties having the same name as those found in the ConnectionStrings configuration section. Here is an example of such a class.

  1. public class ConnectionStringsOptions
  2. {
  3. //Possesses a Default property of type string, just like in appsettings.json
  4. public string Default { get; set; }
  5. }

To finish, we must instruct ASP.NET Core that it must pour the configuration values found in the ConnectionStrings section into an instance of our ConnectionStringsOptions class. So let’s go ahead and add the following line of code in the ConfigureServices method of the Startup class.

  1. //Here we use the GetSection method of the IConfiguration service.
  2. //to get the reference to the ConnectionStrings section
  3. service.Configure<ConnectionStringsOptions>(Configuration.GetSection(“ConnectionStrings”));

THE SOURCES OF CONFIGURATION

The appsettings.json file is just one of the configuration sources we can make use of. ASP.NET Core is already set up to take advantage of others; here they are in order of priority.

  • appsettings.EnvironmentName.json, a json file where we put the specific configuration that the application will use only when it runs in a particular environment (e.g., Development, Production, Staging, …);
  • User secrets, which are ideal for setting up a custom configuration for our development machine. Since the values do not enter the GIT repository, each developer collaborating on the project can have his or her own very personal configuration without affecting others. They are set with the dotnet user-secrets set command “Section:Key” “Value.”
  • Environment variables, are useful when we want to set configuration values that contain sensitive information, such as usernames, passwords, API keys, and so on. Just like user secrets, again the values will not enter the GIT repository and therefore will remain safe on the machine running the application. Remember: use the double underscore __ instead of : as a name separator when indicating the name of the environment variable;
  • Command Line Parameters, is the highest priority source and therefore can redefine the values set in the previous sources. Simply, we need to provide the values at application startup with the dotnet run command –Section:Key=”Value” or, if we are already in production, dotnet MyCourse.dll –Section:Key=”Value.”

Some sources, such as those based on text files, are hot updatable. It means that, for example, we can change a value in the appsettings.json file without then having to restart the application. The updated value will be made available immediately by the IConfiguration and IOptionsMonitor services.

EXTEND THE CONFIGURATION SERVICE

ASP.NET Core is very extensible and therefore also supports other sources of configuration, even created by the developer. If we add the ConfigureAppConfiguration method at the point where the web host is created, in the Program class, we can customize both the sources and their order of priority.

  1. public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
  2. CreateDefaultBuilder(args)
  3. .ConfigureAppConfiguration((context, builder) => {
  4. //Here we set the configuration sources or change their order of priority
  5. })
  6. .UseStartup();

LINK TO CODE ON GITHUB

GITHUB

Download the section12 code or clone the GITHUB repository to have all sections available in your favorite editor.