.NET Core Dependency Injection with Configuration

.NET Core uses dependency injection (DI) intensively, and thus a dependency injection framework is part of its core with Microsoft.Extensions.DependencyInjection. Configuration with .NET Core goes new ways to read configuration information from any configured source, such as JSON, XML, or environmental variables. This can be combined by instantiating the services with DI from configuration information.
In previous blog posts I showed the foundation of DI with Microsoft.Extensions.DependencyInjection, using options with DI, as well as reading configuration using Microsoft.Extensions.Configuration. This article extends these mentioned articles by using configuration information to inject the services.

This article is based on some previous articles, so it’s best to read them first:

Music Mixer

Implementing the Service

Just like the previous implementation of the service, to receive configuration values from configuration files, nothing needs to be changed. Reading the values from configuration files, the constructor is based on the IOptions interface – the same as shown with the previous dependency injection blog post.

public class GreetingService : IGreetingService
{
    public GreetingService(IOptions<GreetingServiceOptions> options)
    {
        _from = options.Value.From;
    }

    private string _from;

    public string Greeting(string name)
    {
        if (name == null) throw new ArgumentNullException(nameof(name));

        return $"Hello, {name}, greetings from {_from}";
    }

The GreetingServiceOptions class defines the information that is retrieved from configuration.

public class GreetingServiceOptions
{
    public string From { get; set; }
}

Using the Service

Using the service, also no changes are needed. The HelloController receives the IGreetingService via dependency injection, and invokes the Greeting method when the Action method of the controller is invoked.

public class HelloController
{
    private readonly IGreetingService _greetingService;

    public HelloController(IGreetingService greetingService)
    {
        _greetingService = greetingService;
    }

    public string Action(string name) =>
        _greetingService.Greeting(name);
}

Extension methods to support configuration

A first change for using configuration files is the extension method AddGreetingService that now accepts an IConfiguration interface as the second parameter. The IConfiguration interface is defined by the NuGet package Microsoft.Extensions.Configuration.Abstractions. With the implementation, compared to the implementation to use options, a different implementation of the Configure method is used to pass the IConfiguration parameter to the IServiceCollection. This version of the extension method is defined in the package Microsoft.Extensions.Options.ConfigurationExtensions.

public static class GreetingServiceCollectionExtensions
{
    public static IServiceCollection AddGreetingService(this IServiceCollection collection, IConfiguration config)
    {
        if (collection == null) throw new ArgumentNullException(nameof(collection));
        if (config == null) throw new ArgumentNullException(nameof(config));

        collection.Configure<GreetingServiceOptions>(config);
        return collection.AddTransient<IGreetingService, GreetingService>();
    }
}

The sample code requires the configuration via the config parameter, that’s why it’s not allowed to pass null which is verified.

To offer using a service in both ways – using the configuration values from configuration files, and passing it directly with the options, you can create both versions of the extension methods AddGreetingService, the one from the previous article and this one.

Defining a Configuration File

The sample code uses a JSON configuration file. However, you can also use XML or INI configuration files, or supply the configration values via environmental variables or program arguments. The sample JSON file defines a value for the From configuration that is defined within GreetingService.

{
  "GreetingService": {
    "From": "Matthias"
  }
}

Building the Dependency Injection Container

What’s left is building the IServiceProvider. With the ServiceCollection, the the AddOptions extension method from Microsoft.Extensions.Options is invoked to add the IOptions service to the dependency injection container. This interface is needed to resolve the constructor parameter of the service. The implementation of the IOptions interface registers the OptionsManager as a singleton to be resolved for the IOptions interface. After registering the HelloController, the extension method AddGreetingService is used, and with the IConfiguration parameter, the service is configured passing the configuration from the GreetingService configuration values.

private static void RegisterServicesWithConfigs()
{
    IConfigurationBuilder configBuilder = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .SetJsonFile("appsettings.json");
    IConfiguration config = configBuilder.Build();

    var services = new ServiceCollection();
    services.AddOptions();
    services.AddTransient<HelloController>();
    services.AddGreetingService(config.GetSection("GreetingService"));

    Container = services.BuildServiceProvider();
}

public static IServiceProvider Container { get; private set; }

Packages needed

For using the .NET Core dependency injection framework with configuration values, the NuGet package Microsoft.Extensions.DependencyInjection is needed for DI. For the configuration, add the package Microsoft.Extensions.Configuration. To read the configuration information from JSON files, the package Microsoft.Extensions.Configuration.Json is required. Finally, to combine DI with configuration, the package Microsoft.Extensions.Options.ConfigurationExtensions needs to be added as well.

Summary

Microsoft.Extensions.DependencyInjection is a new dependency injection framework with .NET Core. It is used with ASP.NET Core applications, but can be used with other technologies such as UWP and WPF as well. Services that need to be constructed passing paramters in the constructor can be either implemented by using the IOptions interface as was described in a previous article, or directly by using configuration values from any configuration source.

Sample code is available with the More Samples from my book Professional C# 6 and .NET Core 1.0.

Have fun with programming and learning!

Christian

More Information

More information about the .NET Core dependency injection and configuration frameworks is available in my new book and my workshops.

Professional C# 6 and .NET Core 1.0

Trainings

Dependency Injection with .NET Core

Dependency Injection with UWP

.NET Core Dependency Injection with Options

Configuration with .NET Core

Music Mixer Photo: image from © Gregsi | Dreamstime.com Music Mixer

One thought on “.NET Core Dependency Injection with Configuration

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s