c# - Autofac Registration technique for this specific issue -
i have class:
public class autofaceventcontainer : ieventcontainer { private readonly icomponentcontext _context; public autofaceventcontainer(icomponentcontext context) { _context = context; } public ienumerable<idomaineventhandler<t>> handlers<t>(t domainevent) t : idomainevent { return _context.resolve<ienumerable<idomaineventhandler<t>>>(); } }
the ieventcontainer
this:
public interface ieventcontainer { ienumerable<idomaineventhandler<t>> handlers<t>(t domainevent) t : idomainevent; }
now ieventcontainer
used in class domainevents
this:
public static class domainevents { .................................... .................................... public static ieventcontainer container; public static void raise<t>(t domainevent) t : idomainevent { if (container != null) foreach (var handler in container.handlers(domainevent)) handler.handle(domainevent); // registered actions, typically used unit tests. if (_actions != null) foreach (var action in _actions) if (action action<t>) ((action<t>)action)(domainevent); } }
my aim have domainevents.container
registered handlers resolved.
public class somemodule : module { protected override void load(containerbuilder builder) { base.load(builder); //wrong way in autofac //because following line ninject-like domainevents.container = new autofaccontainer(componentcontext); //what correct way register achieve above intent? } }
what way in autofac?
you going have memory leak if resolve out of root scope. (see this post overview of lifetime scopes in autofac.) better way this:
interface ieventraiser { void raise<tevent>(tevent @event) tevent : idomainevent; } class autofaceventraiser : ieventraiser { private readonly ilifetimescope context; public autofaceeventraiser(ilifetimescope context) { this.context = context; } public void raise<tevent>(tevent @event) tevent : idomainevent { using(var scope = context.beginlifetimescope("eventraiser")) { foreach(var handler in scope.resolve<ienumerable<idomaineventhandler<tevent>>>()) { handler.handle(@event); } } // scope disposed - no memory leak } } // then, in composition root: icontainer thecontainer = buildtheautofaccontainer(); domainevents.eventraiser = new autofaceventraiser(thecontainer);
this simple answer, there 1 more caveat should aware of...
the question whether want use static ieventraiser
. di purists say, "no - should inject instance of ieventraiser
every class needs one", others have argued static event raiser ok.
be sure aware of how autofac's lifetime scopes work before make decsion, because affect component sharing. example, someclass
has instance of somedependency
, raises someevent
. let assume somedependency
instanceperlifetimescope
.
- if
someclass
getsieventraiser
injected, handlers invoked on same lifetime scope, , injected same instance ofsomedependency
. - if
someclass
uses staticieventraiser
, handlers invoked on different lifetime scope, , injected different instance ofsomedependency
.
you can see why matters if imagine somedependency
db transaction.
Comments
Post a Comment