Автоматическое разрешение зависимостей в .NET Core 2.2 - PullRequest
0 голосов
/ 21 мая 2019

Разве встроенная структура внедрения зависимостей в .NET Core 2.2 не разрешает зависимость и внедряет экземпляр автоматически при создании экземпляра?Или единственный способ внедрить зависимость - это разрешить ее явно при создании нового экземпляра?

Я строю проект библиотеки классов (так что атрибут [FromServices] мне не подходит), где мне кажется, что япридется передавать IServiceProvider почти в конструктор каждого класса.

Я что-то не так понял?

Примечание: фрагмент кода является просто иллюстративным.

public class A
{
    public A()
    {

    }

    public void DoSomethingWithB()
    {
        var b = new B(// To resolve IConfiguration here, I need IServiceProvider. That means I will need to inject IServiceProvider in class A first. Will it go on nesting like this everywhere?);
    }
}

public class B
{
    private IConfiguration _config;
    public B(IConfiguration config)
    {
        _config = config;
    }
    public void DoWork()
    {
        // Use _config here.
    }
}

Ответы [ 2 ]

2 голосов
/ 21 мая 2019

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

public void MyClass(IMyDependency dependency)

Это работа для того, что называется Composition Root, чтобы гарантировать, что все решается сверху. Например. в случае ASP.NET это будет сама инфраструктура, которая будет вызывать Resolve для получения Controller и составления всего дерева объектов, где ваш класс будет иметь прямую или косвенную зависимость от контроллера.

Этот принцип имеет причудливое название "Голливудский принцип": не звоните нам, мы вам звоним. Если вы разрешите зависимость самостоятельно (то есть «позвоните им»), то вы делаете что-то, что вызывает Service Locator, которое считается антипаттерном. Таким образом, вместо этого вы полагаетесь, что кто-то (то есть «вас зовут») внедрит правильную зависимость в ваш класс в некоторой начальной точке входа.

Кроме того, любой дизайн библиотеки классов, которая знает о контейнере DI, в будущем может привести ко многим проблемам, например, если вы захотите, например. проведите модульное тестирование, смените DI-контейнер и т. д. Поэтому вам лучше всего ничего не знать о контейнере.

P.S. Сама Microsoft на самом деле допустила ошибку, когда объединила множество библиотек с контейнером DI (IServiceCollection). Например. библиотеки журналов, фабрика HTTP и т. д. все полагаются на этот контейнер DI для выполнения работы, что делает почти невозможным переключение на другой.

Я понимаю, что это будет намного проще для кого-то использовать его, не понимая DI слишком хорошо, но в долгосрочной перспективе это действительно ограничивает вас и делает, например, модульное тестирование более громоздко.

2 голосов
/ 21 мая 2019

Вы должны зарегистрировать услугу B у поставщика услуг в методе ConfigureServices. Затем вы можете внедрить службу B в службу A, используя обычную конструкторскую инъекцию. Например:

public void ConfigureService(IServiceCollection services)
{
    services.AddSingleton<B>();

    // Other stuff..
}

public class A
{
    private readonly B _b;

    public A(B b)
    {
        _b = b;
    }

    // Use service B in your methods...
}

public class B
{
    private IConfiguration _config;

    public B(IConfiguration config)
    {
        _config = config;
    }
}

Вы можете создавать более глубокие вложенные уровни, если хотите. Например, вы также можете добавить сервис A в контейнер зависимостей (используя services.AddSingleton<A> ()), а затем внедрить сервис A (который автоматически внедрит сервис B и т. Д. И т. Д.) В другой сервис или контроллер .

...