- Home
- .NET tutorials
- How to read the appsettings.json configuration file in ASP.NET Core
How to read the appsettings.json configuration file in ASP.NET Core
Published: Monday 15 March 2021
ASP.NET Core allows for a configuration file to be set up that can be read through the application.
By default, the appsettings.json
file allows for app settings to be configured for a web application.
C# coding challenges
We will have a look at the different ways to read the app configuration file into an ASP.NET Core application.
In addition, we will demonstrate ways of validating the app configuration, how to specify database connection strings and setting up an app configuration file in a console application.
Resources
To try out this application, download the code example from our code examples section.
As well as that, check our video tutorial where we test out how to get the settings from the appsettings.json
file into our ASP.NET Core application.
The appsettings.json File
With ASP.NET, the configuration file used an XML file. Whereas, with ASP.NET Core, it uses the JSON format.
JSON is a lot more compact. No more having to set lengthy opening and closing tags. And that's not forget schemas!
In-turn, that means that the file is easily to read and is a lot more lightweight.
Here is an example of how it looks:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Setting up Custom Configuration
For this part, we are going to set up custom configuration to work in our ASP.NET Core application.
To follow along with this, it's best to create an ASP.NET Core MVC application in Visual Studio 2019.
We are going to set up a RoundTheCodeSync
custom configuration. To do this, we added some settings within the appsettings.json
file, grouped by a RoundTheCodeSync
key.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"RoundTheCodeSync": {
"Title": "Our Sync Tool",
"Interval": "0:30:00",
"ConcurrentThreads": 10
}
}
From there, we can set up an interface and class in our ASP.NET Core MVC application to read our RoundTheCodeSync
custom configuration.
public interface IRoundTheCodeSync
{
string Title { get; set; }
TimeSpan Interval { get; set; }
int ConcurrentThreads { get; set; }
}
public class RoundTheCodeSync : IRoundTheCodeSync
{
public string Title { get; set; }
public TimeSpan Interval { get; set; }
public int ConcurrentThreads { get; set; }
}
Reading our Custom Configuration
There are a number of ways we can read our custom configuration into our ASP.NET Core application.
To demonstrate this, we are going to create an AppSettingsController
in our ASP.NET Core MVC application.
#1: IConfiguration Instance
The first way is to pass the IConfiguration
instance into our AppSettingsController
constructor.
// AppSettingsController.cs
[Route("appsettings")]
public class AppSettingsController : Controller
{
protected readonly IConfiguration _configuration;
public AppSettingsController(IConfiguration configuration)
{
_configuration = configuration;
}
}
With the IConfiguration
instance, we can read the Title
property.
To do this, we have created a FirstWay
action and used the IConfiguration
instance to return the title.
// AppSettingsController.cs
[Route("appsettings")]
public class AppSettingsController : Controller
{
...
[Route("first-way")]
public IActionResult FirstWay()
{
return Content(_configuration.GetSection("RoundTheCodeSync").GetChildren().FirstOrDefault(config => config.Key == "Title").Value, "text/plain");
}
}
However this can be simplified by simply returning the GetValue
method in our IConfiguration
instance:
// AppSettingsController.cs
[Route("appsettings")]
public class AppSettingsController : Controller
{
...
[Route("first-way")]
public IActionResult FirstWay()
{
return Content(_configuration.GetValue<string>("RoundTheCodeSync:Title"), "text/plain");
}
}
#2: Options Pattern
The second way is to add the custom configuration using the options pattern.
From there, we can pass the IOptions
interface through dependency injection, using our custom class as the generic type.
The first thing we need to do is to add the service.
We do that by going into our Startup
class and going to the ConfigureServices
method.
// Startup.cs
public class Startup
{
...
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddOptions<RoundTheCodeSync>().Bind(Configuration.GetSection("RoundTheCodeSync"));
}
}
Then we can inject it into our AppSettingsController
constructor using our IOptions
instance.
// AppSettingsController.cs
[Route("appsettings")]
public class AppSettingsController : Controller
{
...
protected readonly IOptions<RoundTheCodeSync> _roundTheCodeSyncOptions;
public AppSettingsController(..., IOptions<RoundTheCodeSync> roundTheCodeSyncOptions)
{
...
_roundTheCodeSyncOptions = roundTheCodeSyncOptions;
}
...
[Route("second-way")]
public IActionResult SecondWay()
{
return Content(_roundTheCodeSyncOptions.Value.Title, "text/plain");
}
}
#3 Add The Configuration as a Singleton
Another way is to bind the configuration file to our RoundTheCodeSync
class, then add it to dependency injection as a singleton using the IRoundTheCodeSync
interace.
In our Startup class, we need to add the service into DI:
// Startup.cs
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.AddSingleton<IRoundTheCodeSync>((serviceProvider) =>
{
return Configuration.GetSection("RoundTheCodeSync").Get<RoundTheCodeSync>();
});
}
...
}
From there, we can inject our IRoundTheCode
sync interface into our AppSettingsController
constructor, and call the properties directly.
// AppSettingsController.cs
[Route("appsettings")]
public class AppSettingsController : Controller
{
...
protected readonly IRoundTheCodeSync _roundTheCodeSync;
public AppSettingsController(..., IRoundTheCodeSync roundTheCodeSync)
{
...
_roundTheCodeSync = roundTheCodeSync;
}
...
[Route("third-way")]
public IActionResult ThirdWay()
{
return Content(_roundTheCodeSync.Title, "text/plain");
}
}
Validating Configuration
When using a custom configuration in ASP.NET Core, there is also the ability to validate the form using data annotations.
What we've done is modified the RoundTheCodeSync
class and included validation.
The changes we have made include setting a [Required]
data annotation around the Title
property.
In addition, we have set a [Range]
data annotation around the ConcurrentThreads
property between 5 and 15. That means that the ConcurrentThreads
property must be between 5 and 15, otherwise it will throw an error.
// RoundTheCodeSync.cs
public class RoundTheCodeSync : IRoundTheCodeSync
{
[Required]
public string Title { get; set; }
public TimeSpan Interval { get; set; }
[Range(5, 15)]
public int ConcurrentThreads { get; set; }
}
However, adding the data annotations on their own will not validate the configuration.
We need to make a change in our Startup
class.
If we were to pass the configuration with the options pattern (see #2 of Reading our Custom Configuration above), we can append the ValidateDataAnnotations
method to it and this will automatically validate our configuration file.
/ Startup.cs
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
...
services.AddOptions<RoundTheCodeSync>().Bind(Configuration.GetSection("RoundTheCodeSync")).ValidateDataAnnotations();
...
}
...
}
But, if we are passing in the configuration as a singleton (see #3 of Reading our Custom Configuration above), we can use the Validator
class and call the TryValidateObject
method, passing in the configuration file to validate.
If the TryValidateObject
method returns false, we can throw our own custom exception.
// Startup.cs
public class Startup
{
...
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSingleton<IRoundTheCodeSync>((serviceProvider) =>
{
var config = Configuration.GetSection("RoundTheCodeSync").Get<RoundTheCodeSync>();
var valid = Validator.TryValidateObject(config, new ValidationContext(config), new List<ValidationResult>(), true);
if (!valid)
{
throw new Exception("Not all settings are valid.");
}
return config;
});
}
...
}
Creating a Seperate Configuration File
Having a configuration with many settings can be confusing.
This could particularly be the case if we had a large application to maintain.
Fortunately, there is a way in ASP.NET Core to separate the configuration files away from the main appsettings.json
file.
What we would do is to move the RoundTheCodeSync
configuration out of appsettings.json
and into it's own file, which we will call roundthecodesync.json
.
{
"RoundTheCodeSync": {
"Title": "This is the sync",
"Interval": "0:30:00",
"ConcurrentThreads": 12
}
}
After that, we need to go into our Program
class.
When building up our host instance, we can call the ConfigureAppConfiguration
method. Within that, we pass an instance of IConfigurationBuilder
. The IConfigurationBuilder
interface has a AddJsonFile
method, and this is where we can specify our extra configuration file.
{
...
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("RoundTheCodeSync.json",
optional: true,
reloadOnChange: true);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Importing Connection Strings Configuration
ASP.NET Core allows for configuring connection strings.
Quite simply, we specify our connection strings inside the ConnectionStrings
key in our appsettings.json
file.
{
...
"ConnectionStrings": {
"SyncDb": "Server=localhost; Database=RoundTheCodeSync; Trusted_Connection=true; MultipleActiveResultSets=true; Integrated Security=true;"
}
}
From there, we can use our IConfiguration
instance, and call the GetConnectionString
method to get data from our database.
This is an example of how we can use it.
// AppSettingsController.cs
public class AppSettingsController : Controller
{
...
[Route("database")]
public async Task<IActionResult> Database()
{
var name = string.Empty;
using (var conn = new SqlConnection(_configuration.GetConnectionString("SyncDb")))
{
await conn.OpenAsync();
using (var cmd = new SqlCommand("SELECT * FROM dbo.Sync WHERE ID = 1", conn))
{
using (var reader = await cmd.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
name = reader["Name"].ToString();
}
}
}
}
return Content(name, "text/plain");
}
}
Using appsettings.json in a Console Application
It's possible to use the appsettings.json
configuration file in a console application.
In-order to do that, we will need to install the following Nuget packages in our console application to work.
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.Json
Microsoft.Extensions.Configuration.Binder
Microsoft.Extensions.Options
Newtonsoft.Json
From there, in our console application, we can build up an instance of ConfigurationBuilder
, using our appsettings.json
file.
We can also validate the data annotations as well to check that our configuration file is valid.
// Program.cs
class Program
{
static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json").Build();
var roundTheCodeSync = config.GetSection("RoundTheCodeSync").Get<RoundTheCodeSync>();
if (!Validator.TryValidateObject(roundTheCodeSync, new ValidationContext(roundTheCodeSync), new List<ValidationResult>(), true)) {
throw new Exception("Unable to find all settings");
}
Console.WriteLine(roundTheCodeSync.Title);
Console.WriteLine(roundTheCodeSync.Interval);
Console.WriteLine(roundTheCodeSync.ConcurrentThreads);
}
}
Just one thing to note, in a console application, we need to make sure that the appsettings.json
file is being copied to the output directory.
Otherwise, it will not be able to read the file, and will throw an error.
Good Support
So that's how to get going with ASP.NET Core's configuration.
It's good that we can bind settings to strongly typed classes and validate them using data annotations.
In addition, we can separate each group of settings into an individual file and class.
So, it has good support whether we are writing a small application, or one that is a lot more complex.