« Back to home

ASP .NET Core Configuration

Daj się poznać

ASP .NET Core brings with it a lot of new things and concepts to the Web development on .NET framework. One of them is the new way to configure your application. In this post, I will look at the possibilities we have in this area.

In the previous version of ASP .NET you used file Web.config to configure your application. Now you have more options: you can use json, ini, xml and you can even easily use environment variables to configure your app. Let’s see how it works.

We should prepare the configuration for our application during its startup and in the ASP .NET Core there is a class Startup which is the entry point of our app. In the constructor of the class Startup we create the ConfigurationBuilder which we use to prepare the configuration of the app. We can use dependency injection in this constructor and get by it an instance of IHostingEnvironment and IApplicationEnvironment which may be helpful for configuration because IHostingEnvironment provides the current EnvironmentName, WebRootPath, and web root file provider while IApplicationEnvironment provides access to the application properties, such as ApplicationName, ApplicationVersion, and ApplicationBasePath.

I prepared *Startup*’s constructor like this:

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json")
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

    builder.AddEnvironmentVariables();
    Configuration = builder.Build();           
}

What I did in it was to create ConfigurationBuilder and then I ordered it to prepare the configuration based using files “appsettings.json” and appsettings.{env.EnvironmentName}.json but the second file may or may not exist. The part of the name env.EnvironmentName will be replaced in runtime with the proper value. We will see an example of this in a minute.

I also added environment variables to builder so the configuration will also contain what’s in them. After this, I built config and stored it in the property Configuration of Startup class.

Having the setup like this let’s us create files appsettings.json and appsettings.Development.json with content like this:
appsettings.json:

{
    "ClientSettings":{
        "Name": "Client Name",
        "PageSize": 10,
        "ShowTitle": true
    }
}

appsettings.Development.json:

{
    "ClientSettings":{
        "Name": "Development Client Name"
    }
}

Now how can we get access to the values stored in these config files? We have a couple of possibilities so let’s explore a few of them.

The first one is to get it directly from the Configuration property like this:

 var clientName = Configuration["ClientSettings:Name"];

As you can see, you must use colons to get nesting values.

We can even get a whole section from configuration by doing this:

var clientSettings = Configuration.GetSection("ClientSettings");

And then get values from it like this:

var name = clientSettings.Get<string>("Name");
var pageSize = clientSettings.Get<int>("PageSize");
var showTitle = clientSettings.Get<bool>("ShowTitle");

We can also set a default value for a specific property like this:

 var pageSize = clientSettings.Get<int>("PageSize", 20);

We can only do all these things inside Startup class unless we make a Configuration property public static then we can access it also in example controllers like this:

public IActionResult Index()
{
    var clientName = Startup.Configuration["ClientSettings:Name"];
    return Content($"Client {clientName}");
}

…but this kind of using Configuration is a rather bad practice. Another bad practice is making configuration available by dependency injection by doing this in the ConfigureServices:

services.AddInstance<IConfigurationRoot>(Configuration);

And then using it, for example in controller, like this:

public class HomeController : Controller
{
    private IConfigurationRoot _configuration;

    public HomeController(IConfigurationRoot configuration)
    {
        _configuration = configuration;
    }
    public IActionResult Index()
    {            
          var clientName = _configuration["ClientSettings:Name"];
        return Content($"Client {clientName}");
    }
}

We can get configuration in controller in another way but first let’s create a class like this:

public class ClientSettings
{
    public string Name { get; set; }
    public int PageSize { get; set; }
    public bool ShowTitle { get; set; }
}

Then inside ConfigureServices we do something like this:

services.Configure<ClientSettings>(Configuration.GetSection("ClientSettings"));

Now we can get access to the settings for a specific section from dependency injection like this:

public class HomeController : Controller
{
    private ClientSettings _clientSettings;

    public HomeController(IOptions<ClientSettings> clientSettings)
    {
        _clientSettings = clientSettings.Value;
    }
    public IActionResult Index()
    {            
          var clientName = _clientSettings;
        return Content($"{_clientSettings.Name} {_clientSettings.PageSize} {_clientSettings.ShowTitle}");
    }
}

As you can see now, you have access to the strongly typed object with all your desired settings and you can get help from intellisense to see what they contain.

You can even get access to these settings from the view by doing this:

@inject IOptions<ClientSettings> ClientSettings
<div>    
    @if(ClientSettings.Value.ShowTitle) {
        <h3>Page title @ClientSettings.Value.Name</h3>    
    }
</div>

Remember to add usings in the _ViewImports.cshtml like this:

@using AspNetConfigSampleApp
@using Microsoft.Extensions.OptionsModel

For someone who finds injecting IOptions<> a bit awkward, this is a solution which I found out about from Arkadiusz Benedykt. In the ConfigureServices we do this:

var clientSettings = Configuration.Get<ClientSettings>("ClientSettings");
services.AddInstance(clientSettings);

We created an instance of the ClientSettings and registered it as a singleton in the dependency injection container so every time someone asks for the class ClientSettings this instance just created will be injected. With a solution like this, you can use ClientSettings in controller in this way:

public class HomeController : Controller
{
   private ClientSettings _clientSettings;

    public HomeController(ClientSettings clientSettings)
    {
        _clientSettings = clientSettings;
    }
    public IActionResult Index()
    {            
         var clientName = _clientSettings;
        return Content($"{_clientSettings.Name} {_clientSettings.PageSize} {_clientSettings.ShowTitle}");
    }
}

Building the configuration by ConfigurationBuilder is hierarchical. This means that what is added at the beginning of the configuration will be overridden by what’s added later. Usually the last thing we add to the ConfigurationBuilder is AddEnvironmentVariables which means that environmental variables can override settings gathered from previous sources of configuration for example from json files. Let’s see this in practice.

In the file appsettings.Develplment.json I have changed the value for property Name. When I run the application with this command env ASPNET_ENV=”Development” dnx web I get a value for Name like this Development Client Name because the file appsettings.Develplment.json is added after the appsettings.json to the ConfigurationBuilder.

I can even change the value for Name when I run the application by issuing a command like this:

env ASPNET_ENV="Development" ClientSettings:Name="Name from Environment"  dnx web

After this, I got value Name from Environment for property Name of ClientSettings.

We can also change the values in configuration after it is built, for example like this:

Configuration["ClientSettings:Name"] = "Name from Startup";   

We can even add new settings. This is how it is done in the default Web application project template from yo aspnet generator:

Configuration["Data:DefaultConnection:ConnectionString"] = $@"Data Source={appEnv.ApplicationBasePath}/WebApplication.db";

You can find all the examples from this post in this repository. As you can see, this new way of configuring your ASP .NET Core application provides a lot of possibilities. In the future, I will also write about how to deal with settings which should be secret and should not be published to the source code repository.

Related posts:

Comments

comments powered by Disqus