Autofac создать 2 экземпляра службы - PullRequest
0 голосов
/ 24 апреля 2019

Autofac разрешается как 2 отдельных экземпляра, когда я ожидаю один экземпляр на запрос API.

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

Проблема здесь в том, что я не вижу того же экземпляра объекта UserContext , где я внедряю и изменяю через и контроллер Web API в моем обработчике событий домена, который вызывает через DomainEvent.dispatcher.Raise();.

Я следую той же инструкции, что и в Autofac doc.Кто-нибудь может пролить свет на то, что мне здесь не хватает?

Auotfac registration  
 public class AutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
         builder
            .RegisterType<DomainEventDispatcher>()
            .As<IDomainEventDispatcher>().InstancePerLifetimeScope();

         builder.RegisterType<DomainEvent>().As<IDomainEvent> 
       ().PropertiesAutowired().InstancePerLifetimeScope().AutoActivate();
        builder.RegisterType<UserContext>().As<IApplicationContext> 
        ().InstancePerLifetimeScope();
}

}
My DomainEvent class
--------------------------
internal class DomainEvent:IDomainEvent
{
    public static IDomainEventDispatcher dispatcher { get;  set; }

}

1 Ответ

0 голосов
/ 25 апреля 2019

Это будет трудно понять, потому что вы не предоставили Минимальный, Полный и Проверяемый пример .Этот пример и весь код, связанный с вашим вопросом, должны быть в вопросе - если есть вопросы, заданные в комментариях ... обновите ваш вопрос ответами.

Тем не менее, я вижу ловушку, которая, вероятно,вы попадаете в.

Во-первых, я вижу это:

builder
  .RegisterType<DomainEventDispatcher>()
  .As<IDomainEventDispatcher>()
  .InstancePerLifetimeScope();

В ASP.NET / ASP.NET Core это обычно будет равняться «одному экземпляру на запрос», который появляетсябыть тем направлением, куда вы хотите идти.Тем не менее, это означает, что разрешается только из областей времени жизни запроса .

Корневой контейнер также является областью действия времени жизни. Именно здесь разрешаются синглтоны.Здесь также разрешаются одиночные зависимости . Существует много документации по областям жизни.

Это важно, потому что я вижу две другие вещи, которые вызывают некоторое беспокойство.

Сначала ...

internal class DomainEvent : IDomainEvent
{
    public static IDomainEventDispatcher dispatcher { get;  set; }
}

* * * * * * * * * * * * * * * * * * static * * * * * * * * * * * * * * * * * * * * * * * * * * * static действительно относится к , потому что у вас есть диспетчер, зарегистрированный как экземпляр для всей области действия ... но *1030* здесь будет проблемой с многопоточностью.Я предполагаю (хотя и не могу проверить, опять же, из-за отсутствия MCVE), вы делаете что-то такое, что при поступлении запроса вы устанавливаете эту статическую переменную.Это, вероятно, прекрасно работает в процессе разработки, когда за один раз поступает только один запрос.Это будет очень плохой новостью, когда у вас есть два запроса и один экземпляр диспетчера топчет другой экземпляр.

Не смешивайте статический и индивидуальный запрос. Статические вещиодиночки.Всегда.

Секунда ...

builder
  .RegisterType<DomainEvent>()
  .As<IDomainEvent>()
  .PropertiesAutowired()
  .InstancePerLifetimeScope()
  .AutoActivate();

У вас есть то, что выглядит как то, что должно быть создано по запросу, но у вас также есть AutoActivate().Это решит один из этих из корневого контейнера во время сборки контейнера.Я не уверен, что там происходит, может быть, соединение с общими данными запускается или что-то в этом роде, но это означает, что вы получаете DomainEvent разрешение из контейнера во время сборки контейнера, и этот экземпляр будет кэшироваться.пока контейнер не будет удален , потому что вы указали экземпляр для всей области действия ... и, опять же, контейнер является областью действия.Если бы вы запросили второй из них на корневом уровне (например, для зависимости от синглтона), вы бы получили этот корневой, а не на запрос.

Я предполагаю позже вы также получаете DomainEvent объектов, разрешенных где-то.Скорее всего, они поступают из области запроса, если они находятся в контроллерах или что-то в этом роде.

Таким образом, у вас смешанный набор требований для областей и активации.

  • Статическая ссылка наIDomainEventDispatcher, который будет единичным для всего приложения ... но при регистрации области действия для IDomainEventDispatcher.
  • Автоматически активируется для IDomainEvent, что произойдет в корневом контейнере ... ножелание сделать так, чтобы он был за запрос из-за регистрации области действия за всю жизнь.

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

Я бы порекомендовал:

  • Переключить ссылку static на диспетчера набыть свойством экземпляраЕсли вы хотите сделать диспетчер единичным, зарегистрируйте его как SingleInstance в Autofac.
  • Избегайте внедрения свойств, если можете.Если для DomainEvent требуется диспетчер, поместите его в конструктор.Это гарантирует, что вы всегда получите один.Инъекция свойства не завершится ошибкой, если не может внедрить свойство.
  • Не используйте AutoActivate для элементов по запросу.Если у вас есть общедоступное соединение для передачи данных или что-то, что должно быть запущено во время сборки контейнера, выделите эту логику для какого-либо поставщика данных, который может быть зарегистрирован как одиночный.Это также позволит избежать разрешения корневого уровня вещей, которые должны быть по запросу.
...