Внедрение динамических зависимостей в ядро ​​ASP.NET MVC - PullRequest
0 голосов
/ 25 сентября 2018

В моем приложении есть один интерфейс и два подкласса.Два подкласса были зарегистрированы как сервисы.У меня вопрос, как контролировать, какой получить, когда я их использую?

HomeController.cs

public class HomeController : Controller
{
    public interface ITestDI
    {

    }

    public class TestDIClass1: ITestDI
    {
        public TestDIClass1()
        {

        }
    }

    public class TestDIClass2 : ITestDI
    {
        public TestDIClass2()
        {

        }
    }

    ITestDI td;

    public HomeController(ITestDI _td)
    {
        this.td = _td; // how to control which ITestDI implementation will injected with constructor injection? With the configuration below, always get TestDIClass2.
    }

    public IActionResult Index()
    {
        return View();
    }
} 

Startup.cs

services.AddScoped<ITestDI, TestDIClass1>();
services.AddScoped<ITestDI, TestDIClass2>(); // it seems like TestDIClass2 has overwrited the TestDIClass1.

Ответы [ 3 ]

0 голосов
/ 25 сентября 2018

Поскольку вы зарегистрировали более одного экземпляра, вы должны запросить платформу Dependency Injection для IEnumerable<ITestDI> _testDis;

, а затем выполнить итерацию по ней

foreach(var instance in _testDis)
{
    instance.YourMethod();
}
0 голосов
/ 25 сентября 2018

Есть несколько вариантов.

Сначала вы можете отказаться от Auto-Wiring и выполнить регистрацию с использованием делегата следующим образом:

services.AddScoped<TestDIClass1>();    
services.AddScoped<TestDIClass2>();

services.AddTransient<HomeController>(c => new HomeController(
    _td: c.GetRequiredService<TestDIClass2>());   

Здесь вы регистрируете оба ITestDIпо их конкретному типу.Это позволяет делегату для HomeController запрашивать конкретную реализацию, используя GetRequiredService<T>.

. Ручная разводка такого объекта, однако, может стать громоздкой, особенно когда HomeController содержит больше зависимостей, потому что это потребует от васразрешить все зависимости вручную.Таким образом, вместо этого вы можете использовать класс MS.DI ActivatorUtilities.CreateInstance.Он реализует упрощенную форму возможностей Auto-Wiring MS.DI.Следующий фрагмент кода показывает это:

services.AddScoped<TestDIClass1>();    
services.AddScoped<TestDIClass2>();

services.AddTransient<HomeController>(c =>
    ActivatorUtilities.CreateInstance<HomeController>(
        c,                                             
        new object[]                                   
        {                                              
            c.GetRequiredService<TestDIClass2>(),         
        }));

В этом примере HomeController запрашивается из ActivatorUtilities.Для вызова CreateInstance предоставляется экземпляр IServiceProvider (аргумент c) и массив экземпляров для внедрения в конструктор HomeController.ActivatorUtilities сопоставит предоставленные объекты с аргументами конструктора HomeController и разрешит все пропущенные аргументы из предоставленного IServiceProvider.

Использование ActivatorUtilities.CreateInstance позволяет вашей регистрации оставаться неизменной, даже еслиновые аргументы добавляются в конструктор HomeController, например:

public HomeController(
    ILogger logger,          // new argument added
    ITestDI td,
    IProductService service  // another argument added
) 

ActivatorUtilities.CreateInstance выяснит, что разрешенный TestDIClass2 может быть сопоставлен с аргументом конструктора td, и он будетразрешить ILogger и IProductService из IServiceProvider.

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

Эта информация является сокращенной версией еще не изданной книги Внедрение зависимостей в .NET, 2-е издание .Он содержит полную главу о Microsoft.Extensions.DependencyInjection (MS.DI) и около 16 страниц по Работа с несколькими компонентами .Предварительная версия этой главы уже доступна для загрузки.

0 голосов
/ 25 сентября 2018

Можно зарегистрировать конкретный класс.

public HomeController(TestDIClass2 _td)
{
    this.td = _td; //
}
...