.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 parameters 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. My book Professional C# 7 and .NET Core 2.0 has a complete chapter dedicated to dependency injection, and DI is used in many chapters.

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

.NET Core Dependency Injection with Options

Configuration with .NET Core

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

8 thoughts on “.NET Core Dependency Injection with Configuration

  1. Hi. Could you please tell a bit more about configuring ASP.NET Core DI with app.config?
    I have an ASP.NET Core application. I have IMyInterface in that library and one implementation of this interface MyImplementation: IMyInterface in the app. Now I have to have an additional implementation that should be in another library (for tests).
    So how can I use default ASP.NET Core DI container to reach this?

    Like

    1. Thanks for asking. I’m going to write a blog article about how to do this.
      In the meantime, please check the GitHub repository https://github.com/ProfessionalCSharp/MoreSamples in the branch configweb. Here I just created the ASP.NET Core sample https://github.com/ProfessionalCSharp/MoreSamples/tree/configweb/ASPNETCore/ConfigSample using configuration in a library that is configured in the host application.
      Is this what you are looking for?

      Like

Leave a reply to Christian Nagel Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.