Reputation: 6629
This may be something to be solved with Autofac nested scopes, but I have not been able to make enough of the documentation to figure it out myself.
I think what I am looking for is like a per-HTTP-request singleton, but the place of the request is taken by the lifetime of another object.
There is a class SubSystem
, of which a new instance is created (resolved from the container, potentially through a factory class) every time new data is loaded into the application (the old data and SubSystem
instance are discarded).
Then there are classes SomeFeature
, implementing IFeature
, and SomeService
, implementing ISomeService
.
SubSystem
has dependencies on both IFeature
and IService
, while SomeFeature
takes a dependency on IService
. So the object graph looks like this:
SubSystem
└> SomeService : IService <─┐
└> SomeFeature : IFeature ├─── same instance
└> SomeService : IService <─┘
IFeature
is only required in one place, so a transient registration is fine here. IService
on the other hand must be resolved to the same instance for all dependencies within this subgraph, but when new data is loaded and a new SubSystem
instance is created, its subgraph must get its own new "per-request singleton" IService
instance.
The reason for discarding the instances is that they cache information from the loaded data for performance reasons, which will not be valid anymore when new data is loaded. I am currently using real singleton instances that have their local state reset via an event raised in the SubSystem
constructor, but that is clearly a less than optimal solution.
As I said, I'd like this to work like InstancePerHttpRequest()
, but as "instance per SubSystem
".
Is there a way to achieve this using the Autofac API?
Upvotes: 2
Views: 387
Reputation: 31757
The option I think you're looking for is:
.InstancePerOwned<SubSystem>()
If you only consume SubSystem
in one place, just take a dependency on Owned<SubSystem>
at that point, and make sure you Dispose()
the Owned<T>
in the consuming component's Dispose()
method.
For something a bit more transparent, assuming you can create ISubSystem
to go with SubSystem
you can do this:
builder.RegisterType<SubSystem>()
.InstancePerOwned<SubSystem>();
builder.RegisterType<SubSystemGraph>()
.As<ISubSystem>()
// Appropriate sharing here...
;
Where SubSystemGraph
is:
class SubSystemGraph: ISubSystem, IDisposable
{
readonly Owned<SubSystem> _root;
public SubSystemGraph(Owned<SubSystem> root)
{
_root = root;
}
public void Dispose()
{
_root.Dispose();
}
// Methods of ISubSystem delegate to _root.Value
public void Foo()
{
_root.Value.Foo();
}
}
(This could be packaged up into a nicer interface on Autofac but it's not all that common in practice.)
Upvotes: 3