This article discusses about what is delayed instantiation and how it can be used with .NET’s default IoC container and Autofac.
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
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.
Our Approach
Lazy<T> class has a constructor which accepts Func<T> delegate as overload. This delegate is used by Lazy
to provide the instance of T.
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.
Services
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.
Startup
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.
Home Controller
Now, inject the dependencies using LazyInstance
class in the constructor of HomeController
class.
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.
Manoj, thanks a lot for the series on DI. I’m new to .NET and all the beginner tutorials confused me because I could not understand what was going on on start up (configuring services, etc.) So I got kind of stuck. Now I have a much better understanding and can move further with learning .NET platform.
I am glad that this content helped. You can also check my github profile, where the articles are lined up and grouped as per topic , it may be helpful if you are learning .NET Core APIs. Also if you are learning C#, then you can check my YouTube channel too. Let me know if any feedback in the comments or on twitter !