You don't need IConfiguration outside Startup
Tags: net, aspnetcore
Published: 2020-01-20 18:17:31

---
title: You don't need IConfiguration outside Startup
published: true
date: 2020-01-15 17:53:00 UTC
tags: .NET,ASP.NET Core
canonical_url: https://galdin.dev/blog/you-dont-need-iconfiguration-outside-startup/
---

I'm writing this for those new to ASP.NET Core, based on what I see on StackOverflow. Most of what I've written here is already in the Docs, so check the links at the end of the post for detailed info.

## The ASP.NET Core Web Host

Think of the web host as an instance of an application server that processes incoming web requests. We create one (usually in `Program.cs`) as follows:

```csharp
public static void Main(string[] args) => 
    CreateHostBuilder(args).Build().Run();

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
            webBuilder.UseStartup<Startup>()
        );
```

The `CreateDefaultBuilder()` sets up the app's configuration. [Source (v3.0.0)](https://github.com/aspnet/AspNetCore/blob/v3.0.0/src/DefaultBuilder/src/WebHost.cs#L168-L190). The app's configuration is represented by the `IConfiguration` interface. (You can also manually create your own `WebHostBuilder` instance if the defaults don't work for you, in which case you're responsible for setting up the app configuration.)

When the `WebHost` is built using `Build()`, your startup class's `ConfigureServices()` is called. See [WebHostBuilder.cs L187](https://github.com/aspnet/AspNetCore/blob/v3.0.0/src/Hosting/Hosting/src/WebHostBuilder.cs#L175), [WebHost.cs L110](https://github.com/aspnet/AspNetCore/blob/v3.0.0/src/Hosting/Hosting/src/Internal/WebHost.cs#L118) and [WebHost.cs L180](https://github.com/aspnet/AspNetCore/blob/v3.0.0/src/DefaultBuilder/src/WebHost.cs#L168-L190).

## Using IConfiguration in Startup

You can get an instance of `IConfiguration` for use in your Startup class by constructor injection:

```csharp
public class Startup
{
    private IConfiguration Configuration { get; }
    public Startup(IConfiguration configuration) // <-- the framework injects
                                                 // a valid instance
    {
        Configuration = configuration; // <-- and we save that
    }
    
    // rest of the class ...
}

```

The whole point of `IConfiguration` is to provide a way through which the .NET Core app can read configuration from different sources: configuration files, environment variables, command line arguments, etc.

## Using IConfiguration outside Startup

You can also inject an `IConfiguration` instance almost anywhere:

```csharp
public class EmailSender 
{
    private string ClientKey { get; }
    private string ClientSecret { get; }
    
    public EmailSender(IConfiguration configuration)
    {
        ClientKey = configuration["ClientKey"];
        ClientSecret = configuration["ClientSecret"];
    }
    
    // rest of the class follows...
}
```

Let's just stop for a while and imagine an example: we're in a controller's action and need to send an email. We get an `EmailSender` instance from DI, and use it to send the email. The `EmailSender` gets email credentials from the `IConfiguration` abstraction. It doesn't need to know where it's coming from: appsettings.json, command-line arguments, environment variables, azure vault storage– could be coming from anywhere and `EmailSender` doesn't need to care about it.

There are still areas left wanting though:

1. The configuration is not strongly typed: non-string values will need to be manually parsed.
2. The email sender above requires `ClientKey` and `ClientSecret` to be defined using the exact configuration keys. So `EmailSender` is sort-of coupled with the way the actual configuration is set.

The solution to these is the Options Pattern.

## Options Pattern

Think of this as an additional layer of abstraction. In the `EmailService` example, we'd replace `IConfiguration` with `IOptions`. `IConfiguration` knew how to get the right configuration from the right places for you, `IOptions` knows how to get the relevant configuration from `IConfiguration` for you.

Here's a simplified way to use it:


1. Group related settings together in your `appsettings.json`:
    ```javascript
    {
      "Email": { // <-- settings grouped under "Email"
        "ClientKey": "xxx",
        "ClientSecret": "xxx"
      }
    }

    ```
2. Create a class to hold those settings:
    ```csharp
    public class EmailOptions
    {
        public string ClientKey { get; set; }
        public string ClientSecret { get; set; }
    }
    ```
3. Register the Options with the DI container:
    ```csharp
    services.Configure<EmailOptions(Configuration.GetSection("EmailOptions"));
    ```
4. Inject it into the service that needs it:
    ```csharp
    public class EmailSender 
    {
        private string ClientKey { get; }
        private string ClientSecret { get; }

        public EmailSender(IOptions<EmailOptions> options) // <-- here
        {
            ClientKey = options.Value.ClientKey;
            ClientSecret = options.Value.ClientSecret;
        }

        // rest of the class follows...
    }

    ```


Follow this, and you won't see the need to inject `IConfiguration` anywhere outside `Startup`.

* * *

#### Microsoft Docs links:

- [Configuration in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1)
- [Options pattern in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-3.1)
- [ASP.NET Core Web Host](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-3.1)