Glossary
The following terms and definitions are used in this documentation.
Service type | Implementation type
The Service type is usually an interface or an abstract class type used for service resolution or dependency injection. The Implementation type is the actual type registered to the Service type. A registration maps the Service type to an Implementation type. The Implementation type must implement or extend the Service type.
Example where a Service type is mapped to an Implementation type:
container.Register<IService, Implementation>();
The Service type used for requesting a service from the container:
container.Resolve<IService>(); // returns Implementation
Service registration | Registered service
It's an entity created by Stashbox when a service is registered. The service registration stores required information about how to instantiate the service, e.g., reflected type information, name, lifetime, conditions, and more.
In this example, we are registering a named service. The container will create a service registration entity to store the type mapping and the name. During resolution, the container will find the registration by checking for the Service type and the name.
// the registration entity will look like:
// IService => Implementation, name: Example
container.Register<IService, Implementation>("Example");
var service = container.Resolve<IService>("Example");
Injectable dependency
It's a constructor/method argument or a property/field of a registered Implementation type that gets evaluated (injected) by Stashbox during the service's construction.
In this example, Implementation
has an IDependency
injectable dependency in its constructor.
class Implementation : IService
{
public Implementation(IDependency dependency)
{ }
}
Resolution tree
It's the structural representation of a service's resolution process. It describes the instantiation order of the dependencies required to resolve the desired type.
Let's see through an example:
class A
{
public A(B b, C c) { }
}
class B
{
public B(C c, D d) { }
}
class C { }
class D { }
When we request the service A
, the container constructs the following resolution tree based on the dependencies and sub-dependencies.
A
/ \
B C
/ \
C D
The container instantiates those services first that don't have any dependencies. C
and D
will be injected into B
. Then, a new C
is instantiated (if it's transient) and injected into A
along with the previously created B
.
Dependency resolver
It's the container itself or the current scope, depending on which was asked to resolve a particular service. They are both implementing Stashbox's IDependencyResolver
and the .NET framework's IServiceProvider
interface and can be used for service resolution.
Stashbox implicitly injects the current scope wherever IDependencyResolver
or IServiceProvider
is requested.
Root scope
It's the main scope created inside every container instance. It stores and handles the lifetime of all singletons. It's the base of each subsequent scope created by the container with the .BeginScope()
method.
Scoped services requested from the container (and not from a scope) are managed by the root scope. This can lead to issues because their lifetime will effectively switch to singleton. Always be sure that you don't resolve scoped services directly from the container, only from a scope. This case is monitored by the lifetime validation rule when it's enabled.
Named resolution
It's a resolution request for a named service. The same applies, when the container sees a dependency in the resolution tree with a name (set by attributes or bindings); it will search for a matching Named registration to inject.
container.Register<IService, Implementation>("Example");
// the named request.
var service = container.Resolve<IService>("Example");
Self registration
It's a service registration that's mapped to itself. This means its service and implementation type is the same.
// equivalent to container.Register<Implementation, Implementation>();
container.Register<Implementation>();