-
Notifications
You must be signed in to change notification settings - Fork 10
Scopes
A lifetime scope is a unit within your scoped services are being reused and shared by their consumers. It can be interpreted as the unit-of-work pattern where the lifetime scope encapsulates a given unit and the services required for the work are being resolved from it, and when the work finishes the services are being disposed with it.
class Drizzt : IDrow
{
[Dependency("Icingdeath")]
public IWeapon RightHand { get; set; }
[Dependency("Twinkle")]
public IWeapon LeftHand { get; set; }
}
//Register Twinkle as a scoped service
container.RegisterScoped<IWeapon, Twinkle>("Twinkle");
//Register Icingdeath as a singleton service
container.RegisterSingleton<IWeapon, Icingdeath>("Icingdeath");
//Register Drizzt as a transient service
container.RegisterType<IDrow, Drizzt>();
//This will create a scoped instance within the root scope, so it can be interpreted as a singleton
var twinkle = container.Resolve<IWeapon>("Twinkle");
using(var scope = container.BeginScope())
{
//A new 'Twinkle' instance will be injected into Drizzt's left hand,
//cause it was registered as a scoped service and was resolved from a lifetime scope.
//'Icingdeath' will be resolved from the root scope,
//cause it was registered as a singleton.
var drizzt = scope.Resolve<IDrow>();
}
Lifetime scopes are nestable, just think about the Singleton
lifetime which's service is always resolved from the root scope, so it's shared between all scopes.
using(var scope1 = container.BeginScope())
{
using(var scope2 = scope1.BeginScope())
{
//etc...
}
}
The lifetime scope tracks the resolved disposable objects and disposes them when the scope is being disposed. You can control this behavior with some configuration:
//This will include transient objects into the disposal tracking
var container = new StashboxContainer(config => config.WithDisposableTransientTracking());
//This will exclude the given registration from the disposal tracking
container.RegisterType<IDrow, Drizzt>(context => context.WithoutDisposalTracking());
You can also specify a custom action delegate which will be invoked when a scope closes:
//The given delegate will be called when the scope is being disposed, before the registered service's disposal
container.RegisterType<IDrow, Drizzt>(context => context.WithFinalizer(t => t.CallGuenhwyvarBack()));
You also have the ability to put additional services into a given lifetime scope by calling the PutInstanceInScope()
method:
using(var scope = container.BeginScope())
{
scope.PutInstanceInScope<IDrow>(drizzt);
}
Services injected in this way will also being disposed by the scope, except if you set the withoutDisposalTracking
parameter to true
:
using(var scope = container.BeginScope())
{
scope.PutInstanceInScope<IDrow>(drizzt, true);
}
With a child scope you can build up a parent-child relationship between containers. This means you can have a different subset of services present in child and parent containers, if something is missing from a child the parent will be asked to resolve the service:
var container = new StashboxContainer();
//Create a child scope
var child = container.CreateChildContainer();
The child container maintains the lifetime of those services only which were registered into it:
using(var container = new StashboxContainer(config => config.WithDisposableTransientTracking()))
{
//Register to the parent container
container.RegisterType<IDrow, Drizzt>();
IDrow drizzt;
IBarbarian wulfgar;
//Create a child scope
using(var child = container.CreateChildContainer())
{
//Register to the child container
child.RegisterType<IBarbarian, Wulfgar>();
drizzt = child.Resolve<IDrow>();
wulfgar = child.Resolve<IBarbarian>();
} //At the end of the scope only Wulfgar will be disposed because only him was maintained by the child container
}
Child scopes are also nestable:
using(var child1 = container.CreateChildContainer())
{
using(var child2 = child1.CreateChildContainer())
{
//etc...
}
}
- Service registration
- Factory registration
- Assembly registration
- Composition
- Fluent registration api
- Service resolution
- Resolution by attributes
- Conventional resolution
- Delegate resolution
- Conditional resolution
- Multi resolution
- Lifetimes
- Generics
- Generic wrappers
- Decorators
- Resolvers
- Scopes
- Container configuration
- Container diagnostics
- Exceptions