Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Customizing ASP.NET Core Part 2: Configuration

DZone's Guide to

Customizing ASP.NET Core Part 2: Configuration

We continue our series on ASP.NET Core by learning how to configure the applications you develop using this popular C#-based framework.

· Web Dev Zone ·
Free Resource

Jumpstart your Angular applications with Indigo.Design, a unified platform for visual design, UX prototyping, code generation, and app development.

This second part of the blog series about customizing ASP.NET Core is about the application configuration, how to use it, and how to customize the configuration to use different ways to configure your app.

The Series Topics

  • Customizing ASP.NET Core Part 01: Logging
  • Customizing ASP.NET Core Part 02: Configuration
  • Customizing ASP.NET Core Part 03: Dependency Injection
  • Customizing ASP.NET Core Part 04: HTTPS
  • Customizing ASP.NET Core Part 05: HostedServices
  • Customizing ASP.NET Core Part 06: MiddleWares
  • Customizing ASP.NET Core Part 07: OutputFormatter
  • Customizing ASP.NET Core Part 08: ModelBinder
  • Customizing ASP.NET Core Part 09: ActionFilter
  • Customizing ASP.NET Core Part 10: TagHelpers

Configure the Configuration

As well as the logging, since ASP.NET Core 2.0 the configuration is also hidden in the default configuration of the WebHostBuilder and not part of the Startup.cs anymore. This is done for the same reasons to keep the Startup clean and simple:

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)                
            .UseStartup<Startup>();
}

Fortunately, you are also able to override the default settings to customize the configuration in a way you need it.

When you create a new ASP.NET Core project you already have an appsettings.json and an appsettings.Development.json configured. You can and you should use this configuration files to configure your app. You should because this is the pre-configured way and the most ASP.NET Core developers will look for an appsettings.json to configure the application. This is absolutely fine and works pretty well.

But maybe you already have an existing XML configuration or want to share a YAML configuration file over different kind of applications. This could also make sense. Sometimes it makes also sense to read configuration values out of a database.

The next snippet shows the hidden default configuration to read the appsettigns.json files:

WebHost.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((builderContext, config) =>
    {
        var env = builderContext.HostingEnvironment;

        config.SetBasePath(env.ContentRootPath);
        config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
        config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

        config.AddEnvironmentVariables();
    })
    .UseStartup<Startup>();

This configuration also set the base path of the application and adds the configuration via environment variables. The method ConfigureAppConfiguration accepts a lambda method that gets a ConfigurationBuilderContext and a ConfigurationBuilder passed in.

Whenever you customize the application configuration you should add the configuration via environment variable as the last step. The order of the configuration matters and the configuration providers added later will override the previously added configurations. Be sure the environment variables always override the configurations via the file. This way you ensure the configure on Azure web apps via the Application Settings UI on Azure, which will be passed to the application as environment variables.

The IConfigurationBuilder has a lot of extension methods to add more configurations like XML or INI configuration files, in-memory configurations, and so on. You can find a lot more configuration providers provided by the community to read in YAML files, database values, and a lot more. In this demo, I'm going to show you how to read INI files in.

Typed Configurations

Before trying to read the INI files it makes sense to show how to use typed configuration instead of reading the configuration via the IConfiguration key by key.

To read a type configuration you need to define the type to configure. I usually create a class called AppSettings like this:

public class AppSettings
{
    public int Foo { get; set; }
    public string Bar { get; set; }
}

This class can then be filled with specific configuration sections inside the method ConfigureServices in the Startup.cs

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

This way the typed configuration also gets registered as a service in the dependency injection container and can be used everywhere in the application. You are able to create different configuration types per configuration section. In the most cases, one section should be fine, but maybe it makes sense to divide the settings into different sections.

This configuration can then be used via dependency injection in every part of your application. The next snippet shows how to use the configuration in an MVC controller:

public class HomeController : Controller
{
    private readonly AppSettings _options;

    public HomeController(IOptions<AppSettings> options)
    {
        _options = options.Value;
    }

The IOptions<AppSettings> is a wrapper around our AppSettings type and the property Value contains the actual instance of the AppSettings including the values from the configuration file.

To try that out the appsettings.json file, we need to have the AppSettings section configured, otherwise, the values are null or not set.

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "AppSettings": {
      "Foo": 123,
      "Bar": "Bar"
  }
}

Configuration Using INI files

To also use INI files to configure the application we need to add the INI configuration inside the method ConfigureAppConfiguration in the Program.cs file:

config.AddIniFile("appsettings.ini", optional: false, reloadOnChange: true); 
config.AddJsonFile($"appsettings.{env.EnvironmentName}.ini", optional: true, reloadOnChange: true); 

This code loads the INI files the same way as the JSON configuration files. The first line is a required configuration and the second one an optional configuration depending on the current runtime environment.

The INI file could look like this:

[AppSettings] 
Bar="FooBar" 

This file also contains a section called AppSettings and a property called Bar. Initially, I wrote that the order of the configuration matters. If you added the two lines to configure via the INI files after the configuration via the JSON files, the INI files will override the settings from the JSON files. The property Bar gets overridden with "FooBar" and the property Foo stays the same. Also, the values out of the INI file will be available via the previously created AppSettingsclass.

Every other configuration provider will work the same way. Let's see how a configuration provider would look like.

Configuration Providers

A configuration provider is an implementation of an IConfigurationProvider that get's created by a configuration source, which is an implementation of an IConfigurationSource. The configuration provider then reads the date in from somewhere and provides it via a Dictionary.

To add a custom or third-party configuration provider to ASP.NET Core you need to call the Add method on the configuration builder and put the configuration source in:

WebHost.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((builderContext, config) =>
    {
        var env = builderContext.HostingEnvironment;

        config.SetBasePath(env.ContentRootPath);
        config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
        config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

        // add new configuration source
        config.Add(new MyCustomConfigurationSource{
        SourceConfig = //configure whatever source 
            Optional = false,
            ReloadOnChange = true
        });

        config.AddEnvironmentVariables();
    })
    .UseStartup<Startup>();

Usually, you would create an extension method to easier add the configuration source:

config.AddMyCustomSource("source", optional: false, reloadOnChange: true); 

A really detailed concrete example about how to create a custom configuration provider is written by fellow MVP Andrew Lock.

Conclusion

In the most cases, it is not necessary to add a different configuration provider or to create your own configuration provider, but it's good to know how to change it in case you need it. Also using typed configurations is a nice way to read the settings. In classic ASP.NET, we used a manually created façade to read the application settings in a typed way. Now, this is automatically done by just providing a class. This class gets automatically filled and provided via dependency injection.

Take a look at an Indigo.Design sample application to learn more about how apps are created with design to code software.

Topics:
web dev ,asp.net core ,tutorial ,configuration

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}