-
Notifications
You must be signed in to change notification settings - Fork 0
ResolutionBestPractice
Best practice in dependency injection is to allow the container to resolve your services recursively. Prefer the following technique over repeatedly using an IContainer
or IResolvesServices
to resolve many services, stitching them together by hand.
// Some classes we will be considering.
// We will ignore the interface definitions,
// they are not relevant to this example
public class MyTopLevelService : ITopLevelService
{
public MyTopLevelService(IDependencyOne one, IDependencyTwo two)
{ /* Omitted: Do something with these dependencies */ }
}
public class DependencyOne : IDependencyOne
{
public DependencyOne(INestedDependency nested)
{ /* Omitted: Do something with the dependency */ }
}
public class DependencyTwo : IDependencyTwo
{
// No dependencies, parameterless constructor
}
public class NestedDependency : INestedDependency
{
// No dependencies, parameterless constructor
}
// Now the registrations for these services.
container.AddRegistrations(helper => {
helper.RegisterType<MyTopLevelService>()
.As<ITopLevelService>();
helper.RegisterType<DependencyOne>()
.As<IDependencyOne>();
helper.RegisterType<DependencyTwo>()
.As<IDependencyTwo>();
helper.RegisterType<NestedDependency>()
.As<INestedDependency>();
});
// Resolving the top-level service
var myTopLevel = container.Resolve<ITopLevelService>();
In this example the class MyTopLevelService
declares dependency upon IDependencyOne
and IDependencyTwo
by including them as parameters in its constructor. FlexDi will detect this and resolve instances of those dependencies in order to fulfil the resolution of the top-level service. When resolving IDependencyOne
, it will use the class DependencyOne
, which itself declares a dependency upon INestedDependency
. This nested dependency will also be resolved automatically in order to satisfy DependencyOne
.
This recursive resolution will continue as far as possible through the entire object graph of dependencies, until either:
- FlexDi encounters a circular dependency (in which case it will usually raise an exception indicating as much)
- FlexDi encounters a dependent service which it cannot resolve, for example a dependency upon an interface which is not registered
- Note that FlexDi can resolve unregistered classes, if the appropriate option is enabled
- The entire object graph of dependencies is fulfilled, and resolution is successful
Avoid resolving each individual service from the container and then stitching them together 'by hand'. Also, avoid including IContainer
or IResolvesServices
as constructor parameters to your services (then using those to resolve other services). These two practices lead you towards the direction of using the service locator anti-pattern.
In that second scenario (in which your service requires dynamic dependencies) you should consider a factory registration; this allows you to at least keep that logic for dependency selection within your registration (and thus DI) code, instead of spreading dependencies upon MicroDI into your application.