DEV Community

Cover image for Configuring dependency injection in your .NET console application
Pierre Bouillon
Pierre Bouillon

Posted on

Configuring dependency injection in your .NET console application

Dependency injection is a widely used concept in most of the .NET applications. One reason for it may be that it comes straight out of the box in .NET web API but it also provides some important other benefits.

However, when starting a new console application, the dependency injection is not available out of the box, let's add it!

Setup 🧰

The setup is pretty minimal and we only have to create our .NET console application:

~$ dotnet new console -o DepencyInjectionInConsoleApp
Enter fullscreen mode Exit fullscreen mode

Our simple console application 📦

For our example, we will work with a text editor, which will have a spell checker.

Let's start by creating our spell checker:

// ISpellChecker.cs
namespace DependencyInjectionInConsoleApp;

public interface ISpellChecker
{
    bool IsValid(string text);
}

public class VeryBadSpellChecker : ISpellChecker
{
    public bool IsValid(string text)
        => true;
}
Enter fullscreen mode Exit fullscreen mode

We can now create our text editor:

// TextEditor.cs
namespace DependencyInjectionInConsoleApp;

public class TextEditor
{
    private readonly ISpellChecker _spellChecker;

    public TextEditor(ISpellChecker spellChecker)
        => _spellChecker = spellChecker;

    public void Edit(string text)
    {
        if (!_spellChecker.IsValid(text))
        {
            throw new InvalidOperationException("Text is not valid");
        }

        // Process the text

        Console.WriteLine("Text processed");
    }
}
Enter fullscreen mode Exit fullscreen mode

Finally, let's create our editor and call it:

// Program.cs
using DependencyInjectionInConsoleApp;

var spellChecker = new VeryBadSpellChecker();
var textEditor = new TextEditor(spellChecker);

textEditor.Edit("Hello, world!");
Enter fullscreen mode Exit fullscreen mode

Optionally, we can run out program to test our setup:

~/DepencyInjectionInConsoleApp$ dotnet run
Text processed
Enter fullscreen mode Exit fullscreen mode

We're all set !

The issue

In our example we only have a few classes and a single dependency of TextEditor on ISpellChecker but in a real project we would probable have dozens of each.

In that case, creating our objects in the Program.cs file would not be a good solution as it will lead to many lines of code purely dedicated to the creation of objects, something like:

var logger = new SpecificLogger();
var databaseContext = new DatabaseContext(logger);
var spellChecker = new FrenchSpellChecker(logger);
var currentUserService = new CurrentUserService(logger, databaseContext)
var textEditor = new TextEditor(currentUserService, spellChecker);
// and so on
Enter fullscreen mode Exit fullscreen mode

Moreover, if we ever change the dependency of an object, we might have to go through our whole initialization process. Worse, if we are dealing with to different implementation of the same interface, we better be careful:

var spellChecker1 = new FrenchSpellChecker();
var spellChecker2 = new EnglishSpellChecker();
// ...
var englandAmbassyTextEditor = new TextEditor(spellChecker1);
// ^ We probably not meant it to be the french one !
Enter fullscreen mode Exit fullscreen mode

Mixing up dependencies here would be a hard catch since it would be buried under many other lines of code.

That's some problems that dependency injection could have fixed, we better do so!

Bringing dependency injection 💉

When I first faced the challenge of bringing dependency injection in a console application, I expected it to be a harsh process but, to my surprise, it is really not.

First, we would need to add the Microsoft's dependency injection extensions package:

~DepencyInjectionInConsoleApp$ dotnet add package Microsoft.Extensions.DependencyInjection
Enter fullscreen mode Exit fullscreen mode

We can now configure our dependency injection container:

using Microsoft.Extensions.DependencyInjection;

var serviceProvider = new ServiceCollection()
    .AddTransient<ISpellChecker, VeryBadSpellChecker>()
    .AddTransient<TextEditor>()
    .BuildServiceProvider();
Enter fullscreen mode Exit fullscreen mode

And finally, get rid of our manual initialization and retrieve our TextEditor from our dependency injection container:

- var spellChecker = new VeryBadSpellChecker();
- var textEditor = new TextEditor(spellChecker);
+ var textEditor = serviceProvider.GetRequiredService<TextEditor>();
textEditor.Edit("Hello, world!");
Enter fullscreen mode Exit fullscreen mode

We can now run our program once again to verify that nothing changed:

~/DepencyInjectionInConsoleApp$ dotnet run
Text processed
Enter fullscreen mode Exit fullscreen mode

And we're done !

Take aways

Starting from our simple console application, we successfully brought the power of the dependency injection into our project making it more straightforward when invoking objects and easier to update their dependencies.

In this example we used the container provided by Microsoft but they are several others that also exist, chose them according to your needs and feel!

Top comments (1)

Collapse
 
stianhave profile image
Stian HÃ¥ve

Great write-up, thank you!