Настройка инъекции зависимостей в консольном приложении .NET

Инъекция зависимостей — широко используемая концепция в большинстве приложений .NET. Одной из причин этого может быть то, что она поставляется прямо из коробки в .NET web API, но она также предоставляет некоторые другие важные преимущества.

Однако при запуске нового консольного приложения инъекция зависимостей недоступна из коробки, давайте добавим ее!

Установка 🧰

Установка довольно минимальна, и нам нужно только создать наше консольное приложение .NET:

~$ dotnet new console -o DepencyInjectionInConsoleApp
Войти в полноэкранный режим Выход из полноэкранного режима

Наше простое консольное приложение 📦

Для нашего примера мы будем работать с текстовым редактором, который будет иметь проверку орфографии.

Давайте начнем с создания нашей программы проверки орфографии:

// ISpellChecker.cs
namespace DependencyInjectionInConsoleApp;

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

public class VeryBadSpellChecker : ISpellChecker
{
    public bool IsValid(string text)
        => true;
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь мы можем создать наш текстовый редактор:

// 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");
    }
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Наконец, давайте создадим наш редактор и вызовем его:

// Program.cs
using DependencyInjectionInConsoleApp;

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

textEditor.Edit("Hello, world!");
Войти в полноэкранный режим Выйти из полноэкранного режима

По желанию, мы можем запустить программу для проверки нашей настройки:

~/DepencyInjectionInConsoleApp$ dotnet run
Text processed
Войти в полноэкранный режим Выйти из полноэкранного режима

Все готово!

Проблема

В нашем примере у нас всего несколько классов и одна зависимость TextEditor от ISpellChecker, но в реальном проекте у нас, вероятно, будут десятки классов.

В этом случае создание наших объектов в файле Program.cs не будет хорошим решением, так как это приведет к появлению многих строк кода, чисто посвященных созданию объектов, что-то вроде:

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
Войти в полноэкранный режим Выйти из полноэкранного режима

Более того, если мы когда-нибудь изменим зависимость объекта, нам, возможно, придется пройти весь процесс инициализации. Хуже того, если мы имеем дело с различными реализациями одного и того же интерфейса, нам лучше быть осторожными:

var spellChecker1 = new FrenchSpellChecker();
var spellChecker2 = new EnglishSpellChecker();
// ...
var englandAmbassyTextEditor = new TextEditor(spellChecker1);
// ^ We probably not meant it to be the french one !
Вход в полноэкранный режим Выйти из полноэкранного режима

Перепутать зависимости здесь было бы трудно, поскольку они были бы погребены под многими другими строками кода.

Это некоторые проблемы, которые инъекция зависимостей могла бы исправить, и нам лучше это сделать!

Привнесение инъекции зависимостей 💉

Когда я впервые столкнулся с задачей внедрения инъекции зависимостей в консольное приложение, я ожидал, что это будет тяжелый процесс, но, к моему удивлению, это действительно не так.

Во-первых, нам нужно добавить пакет расширений Microsoft для внедрения зависимостей:

~DepencyInjectionInConsoleApp$ dotnet add package Microsoft.Extensions.DependencyInjection
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь мы можем настроить наш контейнер инъекции зависимостей:

using Microsoft.Extensions.DependencyInjection;

var serviceProvider = new ServiceCollection()
    .AddTransient<ISpellChecker, VeryBadSpellChecker>()
    .AddTransient<TextEditor>()
    .BuildServiceProvider();
Войти в полноэкранный режим Выйти из полноэкранного режима

И наконец, избавимся от ручной инициализации и получим наш TextEditor из нашего контейнера инъекции зависимостей:

- var spellChecker = new VeryBadSpellChecker();
- var textEditor = new TextEditor(spellChecker);
+ var textEditor = serviceProvider.GetRequiredService<TextEditor>();
textEditor.Edit("Hello, world!");
Войти в полноэкранный режим Выход из полноэкранного режима

Теперь мы можем запустить нашу программу еще раз, чтобы убедиться, что ничего не изменилось:

~/DepencyInjectionInConsoleApp$ dotnet run
Text processed
Войти в полноэкранный режим Выйти из полноэкранного режима

И мы закончили!

Извлечение уроков

Начиная с нашего простого консольного приложения, мы успешно использовали возможности инъекции зависимостей в нашем проекте, сделав его более простым при вызове объектов и упростив обновление их зависимостей.

В этом примере мы использовали контейнер, предоставленный Microsoft, но существует и несколько других, выбирайте их в соответствии с вашими потребностями и ощущениями!

Оцените статью
Procodings.ru
Добавить комментарий