Как разрешить зависимость в библиотеке классов из контейнера, настроенного в Startup?

Sami спросил: 12 мая 2018 в 05:13 в: c#

Целью является использование IoC и возможность [mock dependencies] для модульного тестирования.

Проект: .NET Core Web API с несколькими библиотеками классов

Я использую Microsoft.Extensions.DependencyInjection для моего IoC, и я бы хотел продолжать использовать его, если он поддерживает то, что я пытаюсь выполнить.

Проблема: по крайней мере один класс в моих сборках (библиотеках классов) зависимость, которую нужно издеваться (например, используя Moq). Я полностью понимаю, что я могу использовать инсталляцию конструктора для ввода интерфейса, но это не соответствует сценарию.

То, что я просто пытаюсь выполнить в своей сборке, - это разрешить зависимость, используя контейнер, который я инициированный в моем классе Startup Web API.

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

Ниже приведен пример кода кода, который, надеюсь, немного разъясняет это.

Startup.cs веб-API (имеет ссылку на сборку, которая определяет принтер).

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IPrinter, Printer>();
}

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

    public interface IPrinter
    {
        void Print(string text);
    }    public class Printer : IPrinter
    {
        public void Print(string text)
        {
            Console.WriteLine("Printing: " + text);
        }
    }    public class Task
    {
        public void PrintSomething(string text)
        {
            //do not 'new up' but resolve it from the container of Startup.cs
            var printer = new Printer(); 
            printer.Print(text);
        }
    }

1 ответ

Nkosi ответил: 13 мая 2018 в 07:22

Это проблема дизайна, замаскированная за проблему XY.

Вы уже сбили принцип явных зависимостей

Методы и классы должны явно потребоваться (обычно через параметры метода или параметры конструктора) любые взаимодействующие объекты, которые им нужны для правильной работы.

public class PrintTask {
    private readonly IPrinter printer;    public PrintTask(IPrinter printer) {
        this.printer = printer;
    }    public void PrintSomething(string text) {
        printer.Print(text);
    }
}

Что позволило бы зависимому классу, уже зарегистрировавшись в контейнере

public void ConfigureServices(IServiceCollection services) {
    services.AddScoped<IPrinter, Printer>();
    services.AddScoped<PrintTask>();
}

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

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