Можно ли продолжать строить ServiceProviders снова и снова? - PullRequest
3 голосов
/ 27 февраля 2020

В приложении. NET Core Console я хочу использовать встроенную инъекцию зависимостей, включая автоматическое c удаление IDisposable объектов в цепочке. В ASP. NET Core объекты создаются и располагаются с каждым запросом, что представляется разумным.

Но в консольном приложении мне нужно создать поставщика услуг, а затем запустить его, получив первый элемент в цепочке от провайдера и работает:

class Program {
    static void Main() {
        using var serviceProvider = new ServiceCollection()
            .AddTransient<Program>()
            .AddTransient<Repository>()
            .AddTransient<MyContext>()
            .BuildServiceProvider();
        serviceProvider.GetService<Program>().Go();
    }

    private readonly Repository _repo;
    public Program(Repository repo) => _repo = repo;

    public void Go() => _repo.Go();
}

public class Repository : IDisposable {
    private readonly MyContext _context;
    public Repository(MyContext context) => _context = context;

    public void Go() => Console.WriteLine("Go!");
    public void Dispose() => Console.WriteLine("Repository Disposed!");
}

public class MyContext : DbContext {
    public override void Dispose() {
        base.Dispose();
        Console.WriteLine("MyContext Disposed!");
    }
}

Когда утилизируется serviceProvider, остальные располагаются также:

Go!
Repository Disposed!
MyContext Disposed!

Если я хочу запустить в процессе oop или с таймером ничего не удаляется до тех пор, пока не будет удален сам поставщик услуг:

for (int i = 0; i < 3; ++i)
{
    serviceProvider.GetService<Program>().Go();
}

Go!
Go!
Go!
Repository Disposed!
MyContext Disposed!
Repository Disposed!
MyContext Disposed!
Repository Disposed!
MyContext Disposed!

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

for (int i = 0; i < 3; ++i)
{
    using var serviceProvider = new ServiceCollection()
        .AddTransient<Program>()
        .AddTransient<Repository>()
        .AddTransient<MyContext>()
        .BuildServiceProvider();

    serviceProvider.GetService<Program>().Go();
}

Go!
Repository Disposed!
MyContext Disposed!
Go!
Repository Disposed!
MyContext Disposed!
Go!
Repository Disposed!
MyContext Disposed!

Мой вопрос: можно ли продолжать строить и утилизировать поставщика снова и снова, как это? Я думаю делать это по таймеру каждые несколько секунд до бесконечности. Это дорогостоящий процесс, и есть ли лучший способ, без необходимости вручную размещать объекты по всей цепочке?

Или это может быть то, что ASP. NET Ядро делает позади в любом случае, воссоздавая провайдера с каждым запросом?

Ответы [ 3 ]

7 голосов
/ 27 февраля 2020

Создайте область, разрешите все зависимости от этого, затем удалите область. Это выглядит примерно так:

using var serviceProvider = new ServiceCollection()
    .AddTransient<Program>()
    .AddTransient<Repository>()
    .AddTransient<MyContext>()
    .BuildServiceProvider();

for (int i = 0; i < 3; ++i)
{
    using var scope = serviceProvider.CreateScope();
    scope.ServiceProvider.GetService<Program>().Go();
}

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

0 голосов
/ 27 февраля 2020

Сборка мусора поможет утилизировать внедренные объекты, если и когда это применимо, поэтому вам не нужно об этом беспокоиться. Создайте stati c ServiceProvider, который вы можете использовать:

static void Main() {
    serviceProvider = new ServiceCollection()
        .AddTransient<Program>()
        .AddTransient<Repository>()
        .AddTransient<MyContext>()
        .BuildServiceProvider();
    serviceProvider.GetService<Program>().Go();
}

private static IServiceProvider serviceProvider;
0 голосов
/ 27 февраля 2020

Короче нет! Я бы определенно избежал воссоздания поставщика услуг каждый раз. Это кажется довольно расточительным.

И нет, ASP. Net DI не работает таким образом, поставщик услуг создается только при запуске приложения.

Если вы измените Program чтобы реализовать IDisposable и изменить l oop на

for (int i = 0; i < 3; ++i)
{
    using(var program = serviceProvider.GetService<Program>()){
        program.Go();
    }
}

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

UNTESTED

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...