-
Notifications
You must be signed in to change notification settings - Fork 10
Service registration
The following example shows how you can bind your service to an interface or abstract base class.
container.Register<ICreature, Elf>();
//or without generic parameters
container.Register(typeof(ICreature), typeof(Elf));
//resolution
var creature = container.Resolve<ICreature>();
//or without generic parameters
var creature = container.Resolve(typeof(ICreature));
The container will resolve the Elf type as an ICreature.
You can also register a service to itself, without specifying a base.
container.Register<Elf>();
//or without generic parameters
container.Register(typeof(Elf));
//resolution
var elf = container.Resolve<Elf>();
//or without generic parameters
var elf = container.Resolve(typeof(Elf));
If you want to bind more implementations to a single service type then you can name your registration in the following way:
container.Register<ICreature, Dwarf>("Bruenor");
container.Register<ICreature, Drow>("Drizzt");
//resolution
var creature = container.Resolve<ICreature>("Bruenor");
As the name is an
object
it can be anything.
In some cases, you may want to use already instantiated services as dependencies:
var elf = new Elf();
container.RegisterInstanceAs<ICreature>(elf);
The container will always return with the prepared instance, when an ICreature is requested.
Stashbox supports the remapping of already registered services:
container.Register<IDwarf, Bruenor>();
container.ReMap<IDwarf, Pwent>();
If there are multiple services mapped to an interface, ReMap will replace all of them with the given one, if you want to replace only one specified service, use the ReplaceExisting() configuration e.g.
container.Register<IDwarf, Bruenor>(context => context.ReplaceExisting());
Similar to the Instance registration except that this type of registration will tell the container, that it should execute further operations (member injection, container extensions, etc.) on the registered instance.
var elf = new Elf();
container.WireUp<ICreature>(elf);
Similar to the WireUp except that the given instance will not be registered into the container.
var elf = new Elf();
var builtElf = container.BuildUp<ICreature>(elf);
If you have some special parameters in your services constructor which you'd like to set manually (primitive types for example, or some pre-evaluated values) you can use injection parameters.
class Drizzt : IDrow
{
public Drizzt(IWeapon leftHand, IWeapon rightHand)
{
//...
}
}
container.Register<IWeapon, Twinkle>();
container.Register<IDrow, Drizzt>(context => context.WithInjectionParameters(new InjectionParameter { Value = new Icingdeath(), Name = "rightHand" });
The configuration above indicates that Stashbox will inject the pre-evaluated Icingdeath object as Drizzts right-hand weapon and the other one will be resolved through the standard registration.
You can also register a service with a factory delegate which gets the current lifetime scope as an argument.
container.Register<IDrow, Drizzt>(context => context.WithFactory(resolver => new Drizzt(resolver.Resolve<IWeapon>("Twinkle"), resolver.Resolve<IWeapon>("Icingdeath")));
container.Resolve<IDrow>(); //the container will use the given factory to instantiate Drizzt.
You can register a Func<>
delegate as a service factory:
container.RegisterFunc<IDrow>(resolver => new Drizzt(resolver.Resolve<IWeapon>()));
Then you can access the registered factory by requesting a Func<>
type:
var factory = container.Resolve<Func<IDrow>>();
var drizzt = factory();
You can also register factory delegates with custom parameters:
container.RegisterFunc<IWeapon, IWeapon, IDrow>((leftHand, rightHand, resolver) => new Drizzt(leftHand, rightHand));
//then request the factory
var factory = container.Resolve<Func<IWeapon, IWeapon, IDrow>>();
var drizzt = factory(new Icingdeath(), new Twinkle());
You can register a service collection with several options:
class Bruenor : IDwarf, ICreature { /*...*/ }
class Drizzt : IDrow, ICreature { /*...*/ }
container.RegisterTypes(new[] { new Drizzt(), new Bruenor() });
The example above will register the services mapped to their impemented interfaces and also themselves, so the mapping will look like:
- ICreature -> Drizzt
- ICreature -> Bruenor
- IDrow -> Drizzt
- IDwarf -> Bruenor
- Drizzt -> Drizzt
- Bruenor -> Bruenor
You can specify a filter which can be used to determine which types you want to register:
container.RegisterTypesAs<IDrow>(new[] { new Drizzt(), new Bruenor() });
In this case only
Drizzt
will be registered into the container.
container.RegisterTypes<IDrow>(new[] { new Drizzt(), new Bruenor() }, type => type == typeof(Bruenor));
In this case only
Bruenor
will be registered into the container.
You can also pass a lambda expression which can be used to customize the registration of each type:
container.RegisterTypes(new[] { new Drizzt(), new Bruenor() }, configurator: context =>
{
if(context.ImplementationType == typeof(Drizzt))
context.WithScopedLifetime();
});
The example above will register
Drizzt
with scoped lifetime and leaves the other services with the default configuration.
You can register services defined within a given assembly:
container.RegisterAssembly(assembly);
In this case all those services which are defined in the given assembly will be registered by their implemented interfaces and base types, and also by themselves.
You can also register an assembly by using just a type defined in it:
container.RegisterAssemblyContaining<Drizzt>();
You can pass an assembly collection also:
container.RegisterAssemblies(new[] { assembly1, assembly2 });
You can specify which services you want to register from an assembly with a filter predicate:
container.RegisterAssembly(assembly, type => type == typeof(Drizzt));
//or
container.RegisterAssemblyContaining<Drizzt>(type => type == typeof(Drizzt));
//or
container.RegisterAssemblies(new[] { assembly1, assembly2 }, type => type == typeof(Drizzt));
You can use the configurator parameter to configure the service registrations:
container.RegisterAssembly(assembly, configurator: context => context.WithScopedLifetime());
Stashbox supports the service registration via ICompositionRoot
implementations.
class DwarfCompositionRoot : ICompositionRoot
{
public void Compose(IStashboxContainer container)
{
container.Register<IDwarf, Bruenor>();
container.Register<IDwarf, Pwent>();
}
}
You can wire up your ICompositionRoot implementation by setting it explicitly during the registration:
container.ComposeBy<DwarfCompositionRoot>();
//... other composition root registrations
You can also let the container find and execute the available ICompositionRoot implementations inside an assembly or assemblies:
container.ComposeAssembly(assembly);
//or
container.ComposeAssemblies(new[] { assembly1, assembly2 });
The container will search for ICompositionRoot implementations inside the given assemblies and will execute their
Compose()
method passing itself as a parameter, so ONLY the services that are registered in them will be wired into the container, any other services inside the assembly/assemblies will be excluded.
- 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