2014-01-31 3 views
0

У меня есть этот класс:Autofac регистрации техника для этой конкретной проблемы

public class AutofacEventContainer : IEventContainer 
    { 
     private readonly IComponentContext _context; 

     public AutofacEventContainer(IComponentContext context) 
     { 
      _context = context; 
     } 

     public IEnumerable<IDomainEventHandler<T>> Handlers<T>(T domainEvent) 
               where T : IDomainEvent 
     { 
      return _context.Resolve<IEnumerable<IDomainEventHandler<T>>>(); 
     } 
    } 

IEventContainer выглядеть следующим образом:

public interface IEventContainer 
    { 

     IEnumerable<IDomainEventHandler<T>> Handlers<T>(T domainEvent) 
      where T : IDomainEvent; 
    } 

Сейчас этот IEventContainer используется в классе DomainEvents как это:

public static class DomainEvents 
    { 

     .................................... 
     .................................... 

     public static IEventContainer Container; 




     public static void Raise<T>(T domainEvent) where T : IDomainEvent 
     { 
      if (Container != null) 
       foreach (var handler in Container.Handlers(domainEvent)) 
        handler.Handle(domainEvent); 

      // registered actions, typically used for unit tests. 
      if (_actions != null) 
       foreach (var action in _actions) 
        if (action is Action<T>) 
         ((Action<T>)action)(domainEvent); 
     } 


    } 

Моя цель состоит в том, чтобы зарегистрировать DomainEvents.Container так, чтобы все обработчики были разрешены.

public class SomeModule : Module 
    { 
    protected override void Load(ContainerBuilder builder) 
     { 
      base.Load(builder); 

      //Wrong way in Autofac 
      //Because the following line is Ninject-like 
      DomainEvents.Container = new AutofacContainer(componentContext); 

      //What is the correct way to register it to achieve the above intent? 

     } 
    } 

Что способ сделать это в Autofac?

ответ

1

У вас возникнет утечка памяти, если вы выйдете из области корневого каталога. (См this post хороший обзор пожизненных областей в Autofac.) А лучший способ сделать это будет выглядеть так:

interface IEventRaiser 
{ 
    void Raise<TEvent>(TEvent @event) where TEvent : IDomainEvent; 
} 

class AutofacEventRaiser : IEventRaiser 
{ 
    private readonly ILifetimeScope context; 

    public AutofaceEventRaiser(ILifetimeScope context) 
    { 
     this.context = context; 
    } 

    public void Raise<TEvent>(TEvent @event) where TEvent : IDomainEvent 
    { 
     using(var scope = context.BeginLifetimeScope("eventRaiser")) 
     { 
      foreach(var handler in scope.Resolve<IEnumerable<IDomainEventHandler<TEvent>>>()) 
      { 
       handler.Handle(@event); 
      } 
     } // scope is disposed - no memory leak 
    } 
} 


// then, in the composition root: 

IContainer theContainer = BuildTheAutofacContainer(); 
DomainEvents.EventRaiser = new AutofacEventRaiser(theContainer); 

Это простой ответ, но есть еще один нюанс, вы должны быть в курсе. ..

Вопрос в том, действительно ли вы хотите использовать статический IEventRaiser. DI пуристы обычно говорят, «нет - вы должны вводить экземпляр вашего IEventRaiser в каждый класс, который нуждается в одном», но другие have argued that a static event raiser is OK.

Убедитесь, что вы знаете, как срок службы прицелы Autofac работают, прежде чем сделать это decsion, потому что это может повлиять на обмен компонентами. Например, скажем, SomeClass имеет экземпляр SomeDependency и он поднимает SomeEvent. Предположим также, что SomeDependency - InstancePerLifetimeScope.

  • Если SomeClass получает IEventRaiser впрыскиваемые, то обработчики будут вызываться на тот же продолжительность жизни объем, и будут введены с тем же экземпляром SomeDependency.
  • Если SomeClass использует статический IEventRaiser, то обработчики будут вызываться в другой области времени жизни и будут введены другим экземпляром SomeDependency.

Вы можете видеть, почему это имеет значение, если вы представляете, что SomeDependency - это что-то вроде транзакции БД.

+0

В 'void Raise (TEvent @event), где T: IDomainEvent;' должен 'T' быть' TEvent'? – Sartorial

+0

@Sartorial yep, fixed –

+0

'BeginLifetimeScope' появляется как неразрешенный символ ... мне не хватает ссылки? Я использую Autofac v3.0 – Sartorial

Смежные вопросы