Delayed Instantiation ?
The dependency injection in .NET allows registering type in IServiceCollection and then those types can be injected in constructors. The IoC container will automatically create the instances of those dependencies. This is called as eager instantiation, meaning the object was created as soon as it was asked (obviously depending on scope of object, container might provide already created object too).
In some applications, some object might resource intensive, consuming a lot of resources. So we may not want to instantiate them eagerly as soon as they are requested. One of the reason behind this might be – that the dependency is required only some of the possible execution flows. So let’s say it is not required in the current flow, then container should not create it at all. This type of instantiation is called as delayed instantiation.
The Lazy Class
The .NET provides a generic class – Lazy<T>, which can be used for delayed instantiation. The class has Value property which provides object of T. When the Value property is accessed for the first time, the instance of dependency T is created.
Autofac container supports delayed instantiation. We need not register Lazy explicitly in the container and we can directly specify Lazy<T> in the constructor, as long as T is registered in container, it will work.
Default .NET IoC Container
.NET’s default IOC container does not have out of the box support for delayed instantiation. So, if delayed instantiation is needed, then some additional steps are required.
Below section discusses a generic approach which can be used anywhere in any application. Let’s go through the code modifications step by step.
For this demo, let’s create a new .NET core MVC web application using Visual Studio.
We will use this constructor and will provide a delegate, which gets the instance of T from .NET’s default IoC container.
Create new LazyInstance <T>
For our generic approach, let’s create a subclass, derived from Lazy<T>. Let’s name it
LazyInstance<T>. As shown in code snippet given below, the
LazyInstance<T> class calls the service provider’s method to get instance from container.
Let’s create an interface and its concrete implementation as shown below. The interface has a method, to retrieve the time at which object was created.
The concrete implementation records the date time at which constructor was called. The same
DateTime value is returned via the method.
Now, let’s go to the Startup class and tell container to use
LazyInstance whenever Lazy<T> is asked. Once this step is done, we can inject
Lazy<T> in any constructor and container would be able to resolve the types correctly.
Also, let’s register the interface and the concrete service as Singleton dependency as shown below.
Now, inject the dependencies using
LazyInstance class in the constructor of
In the Index action, let’s add an option parameter, a
boolean value, which we can use to decide whether to access Value property of
LazyInstance or not.
In Index view, we will print the created on time for the object if the
IsValueCreated property is true. The code for
controller file and
cshtml file is shown below.
Run and Verify
Let’s run the application. The application will show that instance was not created.
When we pass extra querystring parameter and set it to true, the Value property of Lazy would trigger a call to Func<T> delegate. This delegate call would trigger instantiation of the dependency. Thus our index view will be able to show the created on timestamp on UI.
Have you used any other delayed instantiation technique ? Let me know your thoughts.