Configuration

Rick Anderson, Mark Michaelis, Steve Smith, Daniel Roth

The configuration API provides a way of configuring an app based on a list of name-value pairs that can be read at runtime from multiple sources. The name-value pairs can be grouped into a multi-level hierarchy. There are configuration providers for:

  • File formats (INI, JSON, and XML)
  • Command-line arguments
  • Environment variables
  • In-memory .NET objects
  • An encrypted user store
  • Custom providers, which you install or create

Each configuration value maps to a string key. There’s built-in binding support to deserialize settings into a custom POCO object (a simple .NET class with properties).

View or download sample code

Simple configuration

The following console app uses the JSON configuration provider:

using Microsoft.Extensions.Configuration;
using System;
using System.IO;

// Add NuGet <package id="Microsoft.Extensions.Configuration" and
// <package id="Microsoft.Extensions.Configuration.Json"
// .NET Framework 4.x use the following path:
//.SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), @"..\.."))

public class Program
{
    static public IConfigurationRoot Configuration { get; set; }
    public static void Main(string[] args = null)
    {
        var builder = new ConfigurationBuilder()
             .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json");

        Configuration = builder.Build();

        Console.WriteLine($"option1 = {Configuration["option1"]}");
        Console.WriteLine($"option2 = {Configuration["option2"]}");
        Console.WriteLine(
            $"option1 = {Configuration["subsection:suboption1"]}");
    }
}

The app reads and displays the following configuration settings:

{
  "option1": "value1_from_json",
  "option2": 2,

  "subsection": {
    "suboption1": "subvalue1_from_json"
  }
}

Configuration consists of a hierarchical list of name-value pairs in which the nodes are separated by a colon. To retrieve a value, you access the Configuration indexer with the corresponding item’s key:

Console.WriteLine($"option1 = {Configuration["subsection:suboption1"]}");

Name/value pairs written to the built in Configuration providers are not persisted, however, you can create a custom provider that saves values. See custom configuration provider.

The sample above uses the configuration indexer to read values. When the Configuration object is available, the indexer is a convenient way to access setting. To flow information from configuration into other parts of the app outside of Startup, we recommend using the options pattern. We'll show that later in this document.

It's typical to have different configuration settings for different environments, for example, development, test and production. The following highlighted code hooks up two configuration providers to three sources:

  1. JSON provider, reading appsettings.json
  2. JSON provider, reading appsettings.<EnvironmentName>.json
  3. Environment variables provider
public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

See AddJsonFile for an explanation of the parameters. reloadOnChange is only supported in ASP.NET Core 1.1 and higher.

Configuration sources are read in the order they are specified. In the code above, the environment variables are read last. Any configuration values set through the environment would replace those set in the two previous providers.

The environment is typically set to one of Development, Staging, or Production. See Working with Multiple Environments for more information.

Configuration considerations:

  • IOptionsSnapshot can reload configuration data when it changes. Use IOptionsSnapshot if you need to reload configuration data. See IOptionsSnapshot for more information.
  • Configuration keys are case insensitive.
  • A best practice is to specify environment variables last, so that the local environment can override anything set in deployed configuration files.
  • Never store passwords or other sensitive data in configuration provider code or in plain text configuration files. You also shouldn't use production secrets in your development or test environments. Instead, specify secrets outside the project tree, so they cannot be accidentally committed into your repository. Learn more about Working with Multiple Environments and managing Safe storage of app secrets during development.
  • If : cannot be used in environment variables in your system, replace : with __ (double underscore).

Using Options and configuration objects

The options pattern uses custom options classes to represent a group of related settings. We recommended that you create decoupled classes for each feature within your app. Decoupled classes follow:

The options class must be non-abstract with a public parameterless constructor. For example:

public class MyOptions
{
    public MyOptions()
    {
        // Set default value.
        Option1 = "value1_from_ctor";
    }
    public string Option1 { get; set; }
    public int Option2 { get; set; } = 5;
}

In the following code, the JSON configuration provider is enabled. The MyOptions class is added to the service container and bound to configuration.

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        // Set up configuration sources.
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; set; }

    public void ConfigureServices(IServiceCollection services)
    {
        // Adds services required for using options.
        services.AddOptions();

        // Register the IConfiguration instance which MyOptions binds against.
        services.Configure<MyOptions>(Configuration);

        // Add framework services.
        services.AddMvc();
    }

The following controller uses Dependency Injection on IOptions<TOptions> to access settings:

public class HomeController : Controller
{
    private readonly MyOptions _optionsAccessor;

    public HomeController(IOptions<MyOptions> optionsAccessor)
    {
        _optionsAccessor = optionsAccessor.Value;
    }

    public IActionResult Index()
    {
        var option1 = _optionsAccessor.Option1;
        var option2 = _optionsAccessor.Option2;
        return Content($"option1 = {option1}, option2 = {option2}");
    }
}

With the following appsettings.json file:

{
  "option1": "value1_from_json",
  "option2": 2
}

The HomeController.Index method returns option1 = value1_from_json, option2 = 2.

Typical apps won't bind the entire configuration to a single options file. Later on I'll show how to use GetSection to bind to a section.

In the following code, a second IConfigureOptions<TOptions> service is added to the service container. It uses a delegate to configure the binding with MyOptions.

public void ConfigureServices(IServiceCollection services)
{
    // Adds services required for using options.
    services.AddOptions();

    // Register the ConfigurationBuilder instance which MyOptions binds against.
    services.Configure<MyOptions>(Configuration);

    // Registers the following lambda used to configure options.
    services.Configure<MyOptions>( myOptions =>
    {
        myOptions.Option1 = "value1_from_action";
    });

    // Add framework services.
    services.AddMvc();
}

You can add multiple configuration providers. Configuration providers are available in NuGet packages. They are applied in order they are registered.

Each call to Configure<TOptions> adds an IConfigureOptions<TOptions> service to the service container. In the example above, the values of Option1 and Option2 are both specified in appsettings.json, but the value of Option1 is overridden by the configured delegate in the highlighted code above.

When more than one configuration service is enabled, the last configuration source specified “wins”. With the code above, the HomeController.Index method returns option1 = value1_from_action, option2 = 2.

When you bind options to configuration, each property in your options type is bound to a configuration key of the form property[:sub-property:]. For example, the MyOptions.Option1 property is bound to the key Option1, which is read from the option1 property in appsettings.json. A sub-property sample is shown later in this article.

In the following code, a third IConfigureOptions<TOptions> service is added to the service container. It binds MySubOptions to the section subsection of the appsettings.json file:

public void ConfigureServices(IServiceCollection services)
{
    // Adds services required for using options.
    services.AddOptions();

    // Configure with Microsoft.Extensions.Options.ConfigurationExtensions
    // Binding the whole configuration should be rare, subsections are more typical.
    services.Configure<MyOptions>(Configuration);

    // Configure MyOptions using code.
    services.Configure<MyOptions>(myOptions =>
    {
        myOptions.Option1 = "value1_from_action";
    });

    // Configure using a sub-section of the appsettings.json file.
    services.Configure<MySubOptions>(Configuration.GetSection("subsection"));

    // Add framework services.
    services.AddMvc();
}

Using the following appsettings.json file:

{
  "option1": "value1_from_json",
  "option2": -1,

  "subsection": {
    "suboption1": "subvalue1_from_json",
    "suboption2": 200
  }
}

The MySubOptions class:

public class MySubOptions
{
    public MySubOptions()
    {
        // Set default values.
        SubOption1 = "value1_from_ctor";
        SubOption2 = 5;
    }
    public string SubOption1 { get; set; }
    public int SubOption2 { get; set; }
}

With the following Controller:

public class HomeController : Controller
{
    private readonly MySubOptions _subOptionsAccessor;

    public HomeController(IOptions<MySubOptions> subOptionsAccessor)
    {
        _subOptionsAccessor = subOptionsAccessor.Value;
    }

    public IActionResult Index()
    {
        var subOption1 = _subOptionsAccessor.SubOption1;
        var subOption2 = _subOptionsAccessor.SubOption2;
        return Content($"subOption1 = {subOption1}, subOption2 = {subOption2}");
    }
}

subOption1 = subvalue1_from_json, subOption2 = 200 is returned.

IOptionsSnapshot

Requires ASP.NET Core 1.1 or higher.

IOptionsSnapshot supports reloading configuration data when the configuration file has changed. It also has minimal overhead if you don't care about changes. Using IOptionsSnapshot with reloadOnChange: true, the options are bound to IConfiguration and reloaded when changed.

The following sample demonstrates how a new IOptionsSnapshot is created after config.json changes. Requests to server will return the same time when config.json has not changed. The first request after config.json changes will show a new time.

public class TimeOptions
{
    // Records the time when the options are created.
    public DateTime CreationTime { get; set; } = DateTime.Now;

    // Bound to config. Changes to the value of "Message"
    // in config.json will be reflected in this property.
    public string Message { get; set; }
}

public class Controller
{
    public readonly TimeOptions _options;

    public Controller(IOptionsSnapshot<TimeOptions> options)
    {
        _options = options.Value;
    }

    public Task DisplayTimeAsync(HttpContext context)
    {
        return context.Response.WriteAsync(_options.Message + _options.CreationTime);
    }
}

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            // reloadOnChange: true is required for config changes to be detected.
            .AddJsonFile("config.json", optional: false, reloadOnChange: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; set; }

    public void Configure(IApplicationBuilder app)
    {
        // Simple mockup of a simple per request controller that writes
        // the creation time and message of TimeOptions.
        app.Run(DisplayTimeAsync);
    }

    public void ConfigureServices(IServiceCollection services)
    {
        // Simple mockup of a simple per request controller.
        services.AddScoped<Controller>();

        // Binds config.json to the options and setups the change tracking.
        services.Configure<TimeOptions>(Configuration.GetSection("Time"));
    }

    public Task DisplayTimeAsync(HttpContext context)
    {
        context.Response.ContentType = "text/plain";
        return context.RequestServices.GetRequiredService<Controller>().DisplayTimeAsync(context);
    }

    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();
        host.Run();
    }
}

The following image shows the server output:

browser image showing "Last Updated: 11/22/2016 4:43 PM"

Refreshing the browser doesn't change the message value or time displayed (when config.json has not changed).

Change and save the config.json and then refresh the browser:

browser image showing "Last Updated to,e: 11/22/2016 4:53 PM"

In-memory provider and binding to a POCO class

The following sample shows how to use the in-memory provider and bind to a class:

using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;

// Add NuGet  <package id="Microsoft.Extensions.Configuration.Binder"
public class Program
{   
    static public IConfigurationRoot Configuration { get; set; }
    public static void Main(string[] args = null)
    {
        var dict = new Dictionary<string, string>
            {
                {"Profile:MachineName", "Rick"},
                {"App:MainWindow:Height", "11"},
                {"App:MainWindow:Width", "11"},
                {"App:MainWindow:Top", "11"},
                {"App:MainWindow:Left", "11"}
            };

        var builder = new ConfigurationBuilder();
        builder.AddInMemoryCollection(dict);
        Configuration = builder.Build();
        Console.WriteLine($"Hello {Configuration["Profile:MachineName"]}");

        var window = new MyWindow();
        Configuration.GetSection("App:MainWindow").Bind(window);
        Console.WriteLine($"Left {window.Left}");
    }
}
public class MyWindow
{
    public int Height { get; set; }
    public int Width { get; set; }
    public int Top { get; set; }
    public int Left { get; set; }
}

Configuration values are returned as strings, but binding enables the construction of objects. Bindling allows you to retrieve POCO objects or even entire object graphs. The following sample shows how to bind to the MyWindow class and use the options pattern with a ASP.NET Core MVC app:

public class MyWindow
{
    public int Height { get; set; }
    public int Width { get; set; }
    public int Top { get; set; }
    public int Left { get; set; }
}
{
  "AppConfiguration": {
    "MainWindow": {
      "Height": "400",
      "Width": "600",
      "Top": "5",
      "Left": "11"
    }
  }
}

Bind the custom class in ConfigureServices in the Startup class:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyWindow>(
        Configuration.GetSection("AppConfiguration:MainWindow"));
    services.AddMvc();
}

Display the settings from the HomeController:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

public class HomeController : Controller
{
    private readonly IOptions<MyWindow> _optionsAccessor;

    public HomeController(IOptions<MyWindow> optionsAccessor)
    {
        _optionsAccessor = optionsAccessor;
    }
    public IActionResult Index()
    {
        var height = _optionsAccessor.Value.Height;
        var width = _optionsAccessor.Value.Width;
        var left = _optionsAccessor.Value.Left;
        var top = _optionsAccessor.Value.Top;

        return Content($"height = {height}, width = {width}, "
                     + $"Left = {left}, Top = {top}");
    }
}

GetValue

The following sample demonstrates the GetValue<T> extension method:

using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;

// Add NuGet  <package id="Microsoft.Extensions.Configuration.Binder"
public class Program
{   
    static public IConfigurationRoot Configuration { get; set; }
    public static void Main(string[] args = null)
    {
        var dict = new Dictionary<string, string>
            {
                {"Profile:MachineName", "Rick"},
                {"App:MainWindow:Height", "11"},
                {"App:MainWindow:Width", "11"},
                {"App:MainWindow:Top", "11"},
                {"App:MainWindow:Left", "11"}
            };

        var builder = new ConfigurationBuilder();
        builder.AddInMemoryCollection(dict);
        Configuration = builder.Build();
        Console.WriteLine($"Hello {Configuration["Profile:MachineName"]}");

        // Show GetValue overload and set the default value to 80
        // Requires NuGet package "Microsoft.Extensions.Configuration.Binder"
        var left = Configuration.GetValue<int>("App:MainWindow:Left", 80);
        Console.WriteLine($"Left {left}");

        var window = new MyWindow();
        Configuration.GetSection("App:MainWindow").Bind(window);
        Console.WriteLine($"Left {window.Left}");
    }
}

The ConfigurationBinder’s GetValue<T> method allows you to specify a default value (80 in the sample). GetValue<T> is for simple scenarios and does not bind to entire sections. GetValue<T> gets scalar values from GetSection(key).Value converted to a specific type.

Binding to an object graph

You can recursively bind to each object in a class. Consider the following AppOptions class:

public class AppOptions
{
    public Window Window { get; set; }
    public Connection Connection { get; set; }
    public Profile Profile { get; set; }
}

public class Window
{
    public int Height { get; set; }
    public int Width { get; set; }
}

public class Connection
{
    public string Value { get; set; }
}

public class Profile
{
    public string Machine { get; set; }
}

The following sample binds to the AppOptions class:

using Microsoft.Extensions.Configuration;
using System;
using System.IO;

// Add these NuGet packages:
// "Microsoft.Extensions.Configuration.Binder"
// "Microsoft.Extensions.Configuration.FileExtensions"
// "Microsoft.Extensions.Configuration.Json": 
public class Program
{
    public static void Main(string[] args = null)
    {
        var builder = new ConfigurationBuilder()
                   .SetBasePath(Directory.GetCurrentDirectory())
                   .AddJsonFile("appsettings.json");

        var config = builder.Build();

        var appConfig = new AppOptions();
        config.GetSection("App").Bind(appConfig);

        Console.WriteLine($"Height {appConfig.Window.Height}");
    }
}

ASP.NET Core 1.1 and higher can use Get<T>, which works with entire sections. Get<T> can be more convienent than using Bind. The following code shows how to use Get<T> with the sample above:

var appConfig = config.GetSection("App").Get<AppOptions>();

Using the following appsettings.json file:

{
  "App": {
    "Profile": {
      "Machine": "Rick"
    },
    "Connection": {
      "Value": "connectionstring"
    },
    "Window": {
      "Height": "11",
      "Width": "11"
    }
  }
}

The program displays Height 11.

The following code can be used to unit test the configuration:

[Fact]
public void CanBindObjectTree()
{
    var dict = new Dictionary<string, string>
        {
            {"App:Profile:Machine", "Rick"},
            {"App:Connection:Value", "connectionstring"},
            {"App:Window:Height", "11"},
            {"App:Window:Width", "11"}
        };
    var builder = new ConfigurationBuilder();
    builder.AddInMemoryCollection(dict);
    var config = builder.Build();

    var options = new AppOptions();
    config.GetSection("App").Bind(options);

    Assert.Equal("Rick", options.Profile.Machine);
    Assert.Equal(11, options.Window.Height);
    Assert.Equal(11, options.Window.Width);
    Assert.Equal("connectionstring", options.Connection.Value);
}

Simple sample of Entity Framework custom provider

In this section, we'll create a simple configuration provider that reads name-value pairs from a database using EF.

Define a ConfigurationValue entity for storing configuration values in the database:

public class ConfigurationValue
{
    public string Id { get; set; }
    public string Value { get; set; }
}

Add a ConfigurationContext to store and access the configured values:

public class ConfigurationContext : DbContext
{
    public ConfigurationContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<ConfigurationValue> Values { get; set; }
}

Create an class that inherits from IConfigurationSource:

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace CustomConfigurationProvider
{
    public class EFConfigSource : IConfigurationSource
    {
        private readonly Action<DbContextOptionsBuilder> _optionsAction;

        public EFConfigSource(Action<DbContextOptionsBuilder> optionsAction)
        {
            _optionsAction = optionsAction;
        }

        public IConfigurationProvider Build(IConfigurationBuilder builder)
        {
            return new EFConfigProvider(_optionsAction);
        }
    }
}

Create the custom configuration provider by inheriting from ConfigurationProvider. The configuration provider initializes the database when it's empty:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace CustomConfigurationProvider
{
    public class EFConfigProvider : ConfigurationProvider
    {
        public EFConfigProvider(Action<DbContextOptionsBuilder> optionsAction)
        {
            OptionsAction = optionsAction;
        }

        Action<DbContextOptionsBuilder> OptionsAction { get; }

        // Load config data from EF DB.
        public override void Load()
        {
            var builder = new DbContextOptionsBuilder<ConfigurationContext>();
            OptionsAction(builder);

            using (var dbContext = new ConfigurationContext(builder.Options))
            {
                dbContext.Database.EnsureCreated();
                Data = !dbContext.Values.Any()
                    ? CreateAndSaveDefaultValues(dbContext)
                    : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
            }
        }

        private static IDictionary<string, string> CreateAndSaveDefaultValues(
            ConfigurationContext dbContext)
        {
            var configValues = new Dictionary<string, string>
                {
                    { "key1", "value_from_ef_1" },
                    { "key2", "value_from_ef_2" }
                };
            dbContext.Values.AddRange(configValues
                .Select(kvp => new ConfigurationValue { Id = kvp.Key, Value = kvp.Value })
                .ToArray());
            dbContext.SaveChanges();
            return configValues;
        }
    }
}

The highlighted values from the database ("value_from_ef_1" and "value_from_ef_2") are displayed when the sample is run.

You can add an EFConfigSource extension method for adding the configuration source:

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace CustomConfigurationProvider
{
    public static class EntityFrameworkExtensions
    {
        public static IConfigurationBuilder AddEntityFrameworkConfig(
            this IConfigurationBuilder builder, Action<DbContextOptionsBuilder> setup)
        {
            return builder.Add(new EFConfigSource(setup));
        }
    }
}

The following code shows how to use the custom EFConfigProvider:

using System;
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using CustomConfigurationProvider;

public static class Program
{
    public static void Main()
    {
        var builder = new ConfigurationBuilder();
        builder.SetBasePath(Directory.GetCurrentDirectory());
        builder.AddJsonFile("appsettings.json");
        var connectionStringConfig = builder.Build();

        var config = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            // Add "appsettings.json" to bootstrap EF config.
            .AddJsonFile("appsettings.json")
            // Add the EF configuration provider, which will override any
            // config made with the JSON provider.
            .AddEntityFrameworkConfig(options =>
                options.UseSqlServer(connectionStringConfig.GetConnectionString(
                    "DefaultConnection"))
            )
            .Build();

        Console.WriteLine("key1={0}", config["key1"]);
        Console.WriteLine("key2={0}", config["key2"]);
        Console.WriteLine("key3={0}", config["key3"]);
    }
}

Note the sample adds the custom EFConfigProvider after the JSON provider, so any settings from the database will override settings from the appsettings.json file.

Using the following appsettings.json file:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=CustomConfigurationProvider;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "key1": "value_from_json_1",
  "key2": "value_from_json_2",
  "key3": "value_from_json_3"
}

The following is displayed:

key1=value_from_ef_1
key2=value_from_ef_2
key3=value_from_json_3

CommandLine configuration provider

The following sample enables the CommandLine configuration provider last:

using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;

// Add NuGet  <package id="Microsoft.Extensions.Configuration.Binder"
// Add NuGet  <package id="Microsoft.Extensions.Configuration.CommandLine"
public class Program
{
    static public IConfigurationRoot Configuration { get; set; }

    static public Dictionary<string, string> GetSwitchMappings(
    IReadOnlyDictionary<string, string> configurationStrings)
    {
        return configurationStrings.Select(item =>
            new KeyValuePair<string, string>(
                "-" + item.Key.Substring(item.Key.LastIndexOf(':') + 1),
                item.Key))
                .ToDictionary(
                    item => item.Key, item => item.Value);
    }
    public static void Main(string[] args = null)
    {
        var dict = new Dictionary<string, string>
            {
                {"Profile:MachineName", "Rick"},
                {"App:MainWindow:Left", "11"}
            };

        var builder = new ConfigurationBuilder();
        builder.AddInMemoryCollection(dict)
              .AddCommandLine(args, GetSwitchMappings(dict));
        Configuration = builder.Build();
        Console.WriteLine($"Hello {Configuration["Profile:MachineName"]}");

        // Set the default value to 80
        var left = Configuration.GetValue<int>("App:MainWindow:Left", 80);
        Console.WriteLine($"Left {left}");
    }
}

Use the following to pass in configuration settings:

dotnet run /Profile:MachineName=Bob /App:MainWindow:Left=1234

Which displays:

Hello Bob
Left 1234

The GetSwitchMappings method allows you to use - rather than / and it strips the leading subkey prefixes. For example:

dotnet run -MachineName=Bob -Left=7734

Displays:

Hello Bob
Left 7734

Command-line arguments must include a value (it can be null). For example:

dotnet run /Profile:MachineName=

Is OK, but

dotnet run /Profile:MachineName

results in an exception. An exception will be thrown if you specify a command-line switch prefix of - or -- for which there’s no corresponding switch mapping.

The web.config file

web.config is required when you host the app in IIS or IIS-Express. It turns on the AspNetCoreModule in IIS to launch your app. It may also be used to configure other IIS settings and modules. If you are using Visual Studio and delete web.config, Visual Studio will create a new one.

Additional notes

  • Dependency Injection (DI) is not setup until after ConfigureServices is invoked and the configuration system is not DI aware.
  • IConfiguration has two specializations:

    • IConfigurationRoot Used for the root node. Can trigger a reload.
    • IConfigurationSection Represents a section of configuration values. The GetSection and GetChildren methods return an IConfigurationSection.

Additional Resources