You are going to have a memory leak if you resolve out of the root scope. (See this post for a good overview of lifetime scopes in Autofac.) A better way to do it would be like this:
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);
This is the simple answer, but there is one more caveat you should be aware of...
The question is whether you really want to use a static IEventRaiser
. DI purists will generally say, "no - you should inject an instance of your IEventRaiser
into every class that needs one", but others have argued that a static event raiser is OK.
Be sure you are aware of how Autofac's lifetime scopes work before you make this decsion, because it could affect component sharing. For example, say SomeClass
has an instance of SomeDependency
and it raises SomeEvent
. Let us also assume that SomeDependency
is InstancePerLifetimeScope
.
- If
SomeClass
gets theIEventRaiser
injected, then the handlers will be invoked on the same lifetime scope, and will be injected with the same instance ofSomeDependency
. - If
SomeClass
uses a staticIEventRaiser
, then the handlers will be invoked on a different lifetime scope, and will be injected with a different instance ofSomeDependency
.
You can see why this matters if you imagine that SomeDependency
is something like a DB transaction.