Using Dependency Injection in a Console Application
In this post I’ll show you how you can leverage Dependency Injection (DI) in a .NET Core Console Application. I wrote a tutorial on GitHub with source code so you can dive right in.
The wiki for the console application is available here, and the source code for the application can be viewed here. All of the magic happens in Program.cs
of the console application. As you can see, it’s not that much code that is needed, and I’m sure that you can refactor the sample code into a more reusable solution for your needs.
I chose a console application as the platform for this demonstration, because they are pretty bare-bone with the least amount of other code irrelevant to DI and application settings. Once you get the hang of it, it is pretty easy for you to apply the same techniques to virtually any kind of application. For instance an Azure Functions application I wrote about earlier on my blog.
Dependencies
There are actually quite a few dependencies you need to add to your console application. Below is the complete list of dependencies with a short explanation about what role the dependency has for your application.
- Microsoft.Extensions.Configuration – Exposes types such as ConfigurationBuilder that you need for handling configuration settings.
- Microsoft.Extensions.Configuration.Abstractions – Provides interfaces and extension methods needed for configuration handling.
- Microsoft.Extensions.Configuration.Binder – Provides functionality that allows you to bind generic configuration types to data structures that better represent the configuration settings of your application.
- Microsoft.Extensions.Configuration.FileExtensions – Functionality that you need to integrate files and folders to your configuration, like configuration files for instance.
- Microsoft.Extensions.Configuration.Json – Functionality for working with JSON configuration files.
- Microsoft.Extensions.DependencyInjection – Types and implementations that support DI on a general level.
- Microsoft.Extensions.DependencyInjection.Abstractions – Exposes interfaces, extension methods and utilities to support DI.
Reading JSON Configuration Settings
The first thing we need to do is to build our configuration from a JSON file. In this sample, we have the settings stored in the local.settings.json
file. The contents of that file is not of importance. It’s just some imaginary settings for an Azure AD application that our console application might want to identify itself as.
We use a ConfigurationBuilder class instance with its various extension methods to specify the folder our JSON settings file is located in. We also specify the name of that file. Then we build that into an IConfigurationRoot implementation. The source is available here.
Then we create a ServiceCollection instance that will hold all our services. From a DI point of view, our configuration is also a service that other services depend upon. So we add the configuration root as a singleton service to the service collection.
Next, we will map the AzureAd configuration section from our JSON configuration file to an instance of the AzureAdApplicationSettings class. This is done here.
Finally, we add our imaginary GraphService class to the service collection, and build a service provider from the collection.
Using Services
Using these services is pretty straight forward. You just need to have the service provider available. You use the service provider to get services from the collection that implement a particular interface or are of a specific type.
Conclusion
It can be a lot to take in at first, but after a while, it becomes pretty simple actually. You just need to include the right dependencies in your application and just connect the dots.
As you see from the Abstracts and CommonServices class libraries, there are no dependencies to any of the dependencies listed above, that actually do all the magic. What this means is that you can make use of DI even with libraries that perhaps where not designed for dependency injection. The only requirement is that you must pass in the dependencies through the constructors.
0 Comments