Basic usage
This section is about the basics of Stashbox's API. It will give you a good starting point for more advanced topics described in the following sections. Stashbox provides several methods that enable registering services, and we'll go through the most common scenarios with code examples.
Default registration
Stashbox allows registration operations via the Register()
methods.
During registration, the container checks whether the service type is assignable from the implementation type and if not, the container throws an exception.
Also, when the implementation is not resolvable, the container throws the same exception.
The example registers DbBackup
to be returned when IJob
is requested.
- Generic API
- Runtime type API
container.Register<IJob, DbBackup>();
IJob job = container.Resolve<IJob>();
// throws an exception because ConsoleLogger doesn't implement IJob.
container.Register<IJob, ConsoleLogger>();
// throws an exception because IJob is not a valid implementation.
container.Register<IJob, IJob>();
container.Register(typeof(IJob), typeof(DbBackup));
object job = container.Resolve(typeof(IJob));
// throws an exception because ConsoleLogger doesn't implement IJob.
container.Register(typeof(IJob), typeof(ConsoleLogger));
// throws an exception because IJob is not a valid implementation.
container.Register(typeof(IJob), typeof(IJob));
You can register a service to itself without specifying a service type, only the implementation (self registration).
In this case, the given implementation is considered the service type and must be used to request the service (DbBackup
in the example).
- Generic API
- Runtime type API
container.Register<DbBackup>();
DbBackup backup = container.Resolve<DbBackup>();
container.Register(typeof(DbBackup));
object backup = container.Resolve(typeof(DbBackup));
The container's API is fluent, which means you can chain the calls on its methods after each other.
var job = container.Register<IJob, DbBackup>()
.Register<ILogger, ConsoleLogger>()
.Resolve<IJob>();
Named registration
The example shows how you can bind more implementations to a service type using names for identification.
The same name must be used to resolve the named service.
The name is an object
type.
- Generic API
- Runtime type API
container.Register<IJob, DbBackup>("DbBackup");
container.Register<IJob, StorageCleanup>("StorageCleanup");
IJob cleanup = container.Resolve<IJob>("StorageCleanup");
container.Register(typeof(IJob), typeof(DbBackup), "DbBackup");
container.Register(typeof(IJob), typeof(StorageCleanup), "StorageCleanup");
object cleanup = container.Resolve(typeof(IJob), "StorageCleanup");
You can also get each service that share the same name by requesting an IEnumerable<>
or using the ResolveAll()
method with the name
parameter.
container.Register<IJob, DbBackup>("StorageJobs");
container.Register<IJob, StorageCleanup>("StorageJobs");
container.Register<IJob, AnotherJob>();
// jobs will be [DbBackup, StorageCleanup].
IEnumerable<IJob> jobs = container.Resolve<IEnumerable<IJob>>("StorageJobs");
Instance registration
With instance registration, you can provide an already created external instance to use when the given service type is requested.
Stashbox automatically handles the disposal of the registered instances, but you can turn this feature off with the withoutDisposalTracking
parameter.
When an IJob
is requested, the container will always return the external instance.
- Generic API
- Runtime type API
- Named
- No dispose
var job = new DbBackup();
container.RegisterInstance<IJob>(job);
// resolvedJob and job are the same.
IJob resolvedJob = container.Resolve<IJob>();
var job = new DbBackup();
container.RegisterInstance(job, typeof(IJob));
// resolvedJob and job are the same.
object resolvedJob = container.Resolve(typeof(IJob));
var job = new DbBackup();
container.RegisterInstance<IJob>(job, "DbBackup");
// resolvedJob and job are the same.
IJob resolvedJob = container.Resolve<IJob>("DbBackup");
var job = new DbBackup();
container.RegisterInstance<IJob>(job, withoutDisposalTracking: true);
// resolvedJob and job are the same.
IJob resolvedJob = container.Resolve<IJob>();
The instance registration API allows the batched registration of different instances.
container.RegisterInstances<IJob>(new DbBackup(), new StorageCleanup());
IEnumerable<IJob> jobs = container.ResolveAll<IJob>();
Re-mapping
With re-map, you can bind new implementations to a service type and delete old registrations in one action.
When there are multiple registrations mapped to a service type, .ReMap()
will replace all of them with the given implementation type. If you want to replace only one specific service, use the .ReplaceExisting()
configuration option.
- Generic API
- Runtime type API
container.Register<IJob, DbBackup>();
container.ReMap<IJob, StorageCleanup>();
// jobs contain all two jobs
IEnumerable<IJob> jobs = container.ResolveAll<IJob>();
container.ReMap<IJob, SlackMessageSender>();
// jobs contains only the SlackMessageSender
jobs = container.ResolveAll<IJob>();
container.Register(typeof(IJob), typeof(DbBackup));
container.Register(typeof(IJob), typeof(StorageCleanup));
// jobs contain all two jobs
IEnumerable<object> jobs = container.ResolveAll(typeof(IJob));
container.ReMap(typeof(IJob), typeof(SlackMessageSender));
// jobs contains only the SlackMessageSender
jobs = container.ResolveAll(typeof(IJob));
Wiring up
Wiring up is similar to Instance registration except that the container will perform property/field injection (if configured so and applicable) on the registered instance during resolution.
- Generic API
- Runtime type API
container.WireUp<IJob>(new DbBackup());
IJob job = container.Resolve<IJob>();
container.WireUp(new DbBackup(), typeof(IJob));
object job = container.Resolve(typeof(IJob));
Lifetime shortcuts
A service's lifetime indicates how long its instance will live and which re-using policy should be applied when it gets injected.
This example shows how you can use the registration API's shortcuts for lifetimes. These are just sugars, and there are more ways explained in the lifetimes section.
The DefaultLifetime
is configurable.
- Default
- Singleton
- Scoped
When no lifetime is specified, the service will use the container's DefaultLifetime
, which is Transient
by default.
container.Register<IJob, DbBackup>();
IJob job = container.Resolve<IJob>();
A service with Singleton
lifetime will be instantiated once and reused during the container's lifetime.
container.RegisterSingleton<IJob, DbBackup>();
IJob job = container.Resolve<IJob>();
The Scoped
lifetime behaves like a Singleton
within a scope.
A scoped service is instantiated once and reused during the scope's whole lifetime.
container.RegisterScoped<IJob, DbBackup>();
IJob job = container.Resolve<IJob>();