Зарегистрируйте услугу с несколькими жизнями - PullRequest
0 голосов
/ 24 января 2020

В приложении. Net Core 2.2 мне нужна версия службы как временная, а версия как область действия.

Для "обычной" службы я мог бы создать два разных интерфейса, зарегистрировать один как кратковременный и один как ограниченный, но если обоим нужен DbContext, это будет означать, что мне нужно будет создать два DbContext (да, один может быть просто оболочкой) и зарегистрировать оба, но это чувствует неправильным.

Я использую do tnet Базовую структуру ядра Dependency Injection, с которой я не очень знаком. В UnityIo C я мог бы легко сделать это, используя именованные регистрации:

//Note: Pseudo-code
void Register(IUnityContainer container)
{   
    container.RegisterType<IMyInterface, MyClass>(
        "Transient",
        new TransientLifetimeManager()
        new InjectionConstructor(
            new ResolvedParameter<MyDbContext>("Transient")));

    container.RegisterType<IMyInterface, MyClass>(
        "PerResolve",
        new "PerResolve", new PerResolvedLifetimeManager()()
        new InjectionConstructor(
            new ResolvedParameter<MyDbContext>(PerResolve)));

    container.RegisterType<MyDbContext>("Transient", new TransientLifetimeManager());
    container.RegisterType<MyDbContext, MyClass>("PerResolve", new PerResolvedLifetimeManager());
}

Бонусные баллы: Используя IServiceProvider, как мне запросить переходное разрешение по сравнению с разрешением в области?

1 Ответ

1 голос
/ 25 января 2020

Самый простой способ реализовать это - использовать два интерфейса, как показано в следующем примере:

interface IMyScopedInterface
{
    void Foo();
}

interface IMyTransientInterface
{
    void Foo();
}

class MyClass : IMyTransientInterface, IMyScopedInterface
{
    public MyClass(MyDbContext dbContext)
    {
    }

    public void Foo()
    {
    }
}

, а затем зарегистрировать свой класс с помощью следующего:

services.AddTransient<IMyTransientInterface, MyClass>();
services.AddScoped<IMyScopedInterface, MyClass>();

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

  1. Для начала система DI пытается получить экземпляр IMyScopedInterface (обычно потому, что Система DI пытается создать экземпляр какой-либо другой службы, конструктор которой принимает параметр IMyScopedInterface.
  2. Поскольку IMyScopedInterface был зарегистрирован с временем жизни с ограничениями, система DI сначала просматривает свою коллекцию служб, которые уже был создан экземпляр для текущей области, чтобы увидеть, создал ли он уже IMyScopedInterface. Этот поиск происходит с пустыми руками, поэтому система DI затем переходит к созданию нового экземпляра MyClass.
  3. . Для этого он проверяет конструктор MyClass и определяет, что ему необходим * 1021. *, поэтому он возвращается через этот же поток для получения MyDbContext.
  4. Система DI создает экземпляр MyClass, предоставляющий полученный MyDbContext, и затем кэширует этот MyClass объект как часть текущей области, так что последующие запросы на IMyScopedInterface в той же области могут получить общий объект.

Тот же самый поток c остается верным для IMyTransientInterface за исключением того, что DI система не беспокоится о поиске ранее созданного экземпляра объекта, и после создания нового экземпляра MyClass она вообще не кеширует его.

Надеемся, что из этого потока следует понять, что на самом деле не имеет значения, какова продолжительность жизни MyDbContext. Если он зарегистрирован как временный, то каждый новый экземпляр MyClass получит свой уникальный экземпляр MyDbContext. Если срок действия MyDbContext ограничен (что является поведением по умолчанию в Entity Framework), то все экземпляры MyClass, созданные в данной области, будут использовать один экземпляр MyDbContext независимо от того, были ли экземпляры MyClass создается для IMyScopedInterface или IMyTransientInterface.

...