In this chapter, we will cover how we can use configuration in ASP.Net Core 3. But before diving in, let’s see for a moment how it looked in plain old ASP.Net
Configuration before .Net Core
In old ASP.Net configuration was handled typically in only one XML file – Web.config. It was a place where everything was placed. From connection strings to assembly versions and detailed framework settings. This file got bigger and bigger while our project grew and was hard to read. Luckily you could use different files if you link them in the Web.config. Here is how the most important part of this file looked like:
The XML format was perfectly readable, but you would need to follow a specific convention. Let’s now see how things changed in .Net Core.
New possibilities
In .Net Core 3 things are completely different:
- configuration can be stored in many files and most common format is JSON
- we can follow our own format
- we can have nesting
- configuration can be parsed to whole classes with nested objects
- we can make configuration refreshable when an application is running, without the need to restart it
Instead of having a configuration in an XML format, in .Net Core we have much more possibilities. Here are the sources that we can use(that are supported by default by the framework):
- Azure Key Vault
- Azure App Configuration
- Command-line arguments
- Directory files (INI, JSON, XML)
- Environment variables (by default prefixed by DOTNET_)
- In-memory .Net objects
- Settings files
- and custom providers
Note that variables can be overridden when another source provides the same variable. Then an order that we apply configuration with is important.
One more thing – we can have different configurations for the environment. In order to achieve that, we can suffix our configuration files with environment names. We have environment names set by the framework to: development, staging, production. So we can name our files like this:
- appsettings.json – that would contain development variables
- appsettings.production.json – that would contain production variables
Let’s use a configuration in .Net Core 3
First, let’s have an example of an appsettings.json configuration file:
In this configuration file, I have an Email section for configuration to send e-mails. In order to fetch the whole configuration at once, I’ll add three classes:
public class ServiceConfiguration { public ConnectionStringsConfiguration ConnectionStrings { get; set; } public EmailConfiguration Email { get; set; } } public class EmailConfiguration { public string SmtpServerAddress { get; set; } public int SmtpServerPort { get; set; } public string SenderAddress { get; set; } } public class ConnectionStringsConfiguration
{
public string DB { get; set; }
}
ServiceConfiguration represents whole configuration and EmailConfiguration represents Email section.
Let’s now go to my Startup class. IConfiguration is an interface for handling configuration, provided by the framework and registered in DI by default. In ConfigureServices we can bind configuration and register it in Dependency Injection container.
public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { // configuration var serviceConfiguration = new ServiceConfiguration(); Configuration.Bind(serviceConfiguration); services.AddSingleton(serviceConfiguration); }
Notice that we need just those 3 lines to make it work. Now let’s see how we can implement class, that would send e-mails.
public class EmailSenderService : IEmailSenderService { private readonly EmailConfiguration emailConfiguration; private readonly SmtpClient _client; public EmailSenderService(ServiceConfiguration configuration) { emailConfiguration = configuration.Email; _client = new SmtpClient(emailConfiguration.SmtpServerAddress, emailConfiguration.SmtpServerPort); } public async Task SendEmail(string emailAddress, string content) { var message = new MailMessage(emailConfiguration.SenderAddress, emailAddress) { Subject = content }; await _client.SendMailAsync(message); } }
This is programming pleasure in its purest form. Notice what we are injecting ServiceConfiguration, that is our representation of configuration in code. We do not need to use or parse JSON files, digg for nested variables. We just fetch configuration the way we defined it – simple.
What you don’t need to do
In many tutorials and even in official Microsoft documentation you could see, that in order to read appsettings.json file, you would need to make this change in Program.cs file:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { config.AddJsonFile("appsettings.json"); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
The truth is that appsettings.json file will be read by default by the framework without using ConfigureAppConfiguration.
This can cause you problems when deploying to Azure. When I was doing it for the first time it took me hours to figure that out. I set up variables in App Sevice configuration, but they were overridden by local appsettings.json file because of this line. This configuration was applied after reading the configuration from App Service. You can safely remove this line.
Hope you enjoyed this post, you can have a look at the code posted here on my Github:
https://github.com/mikuam/TicketStore