-
Notifications
You must be signed in to change notification settings - Fork 0
Resolution
The way in which FlexDi resolves services is typically quite simple, but the actual results depend very much upon the way in which the container is configured. The absolute simplest possible configuration (with every option disabled) uses the core resolution process; enabled options extend that process.
Throughout this page, a "resolution request" can mean either a direct call to IResolvesServices.Resolve
(or related method) or it might mean the recursive resolution of a parameter (described in the core resolution process). The parameters to a resolution request are a service type and a name.
The options mentioned here are described on the configuration page. In each case in this list, if the criteria are not met (such as the option is not enabled, or the resolution request is not for the appropriate service type) then control falls through to the next step.
- If the SelfRegisterAResolver option is enabled and the requested type is
IResolvesServices
then an object is returned which may itself be used to resolve further services. - If the SupportResolvingNamedInstanceDictionaries option is enabled and the requested type is
IDictionary<TKey,TValue>
then a named instance dictionary is created and returned for the givenTValue
service type. A named instance dictionary contains resolved instances all of the available registered types which could satisfy the requested service type (TValue
), indexed by their registered name (TKey
). - If the requested type is
string
and the name parameter of the request is"registeredName"
then the resolver will resolve the name under which the previous resolution was performed. See the section on injecting the registered name, below. - If the SupportResolvingLazyInstances option is enabled and the requested type is
Lazy<T>
then a lazily-resolved instance will be returned as the result of resolution. When the value is created from the lazy instance the resolution ofT
will be completed, using the same name as the request for the lazy instance. - Unless the ThrowOnCircularDependencies option is disabled (we suggest that it is not), the resolution request will be checked for circular dependencies.
- If the UseInstanceCache option is enabled and the result of the registration to be resolved has been cached, then that same object instance is returned from a cache associated with the container. In this case, further resolution ceases.
- The core resolution process is triggered, if the operation has gotten this far.
- If core resolution is a success and the UseInstanceCache option is enabled, then the resolved object instance is added to the cache.
- If the container has a parent container then if resolution has not yet succeeded this resolution process is begun again with step 1, from the parent container. This occurs recursively until either resolution succeeds or there are no more parent containers
- If the ResolveUnregisteredTypes option is enabled, the current container is the most deeply-nested container in the resolution operation (IE: has no children) and the requested service type is a non-abstract class then an attempt will be made to resolve an instance of that class without using a registration.
- This operates exactly as if the current container had a type registration for that type (except no registration is needed).
- If this registration-less resolution is a success and the UseInstanceCache option is enabled, then the resolved object instance is added to the cache.
- If the option MakeAllResolutionOptional is enabled, then the resolution is simply converted to a successful result. The result of the resolution is the default for the service type being resolved; typically
null
. Thus, where this option is enabled, resolution will always be successful unless an exception occurs. - If the operation has still not succeeded to resolve an object then resolution has failed:
- If the current resolution operation is part of a recursive resolution operation, resolving a parameter of a factory delegate or a type constructor then an exception is raised.
- If the current resolution operation is being performed directly from a
IResolvesServices.TryResolve
method call then it will return false. - If the current resolution operation is being performed directly from a
IResolvesServices.Resolve
method call then it will raise an exception.
Consider this example, which might be the best way to see how 'injecting' the registered name works. This will also work using parameter names, for recursive resolutions.
// A class
public class GreetingService
{
readonly string name;
public string Greet() => $"Hello {name}!";
public GreetingService(string registeredName)
{
name = registeredName;
}
}
// Registration
container.AddRegistrations(helper => {
helper.RegisterType<GreetingService>();
});
// Resolution
var greeter = container.Resolve<GreetingService>("Jane");
// The result will be "Hello Jane!"
greeter.Greet();
A circular dependency may occur during a recursive resolution operation. When resolving a dependency via a registration, if that same recursive resolution operation has previously required a duplicate registration then a circular dependency is detected. This will raise an exception.
Registrations are considered duplicates for the purpose of detecting circular dependencies if:
- They are for the exact same service type
- And either:
- The previously-used registration has the same name as the registration currently being resolved
- The registration currently being resolved has no name
It is possible to nest IContainer
instances, via the method CreateChildContainer
. This creates a new container instance which inherits all of the registrations of the parent. Within a child container, it is possible to provide additional registrations or even to override the registrations in the parent, by registering them again with different parameters.
When caching is used, each container has its own cache and services are cached within the same container in which they were registered. When a container is disposed, only services registered and cached within the disposed container are disposed along with it. Services registered in and cached in a parent container are kept 'alive' until their associated container is disposed.