Dependency injection in ASP.NET Core
ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies.
Let’s learn about the basics of dependency injection.
A dependency is an object that another object depends on. Examine the following SomeService class with a WriteSomething method that other classes depend on:
A class can create an instance of the SomeService class to make use of its WriteSomething method. In the following example, the SomeService class is a dependency of the ViewModelService class:
The class creates and directly depends on the SomeService class. Code dependencies, such as in the previous example, are problematic and should be avoided for the following reasons:
- To replace SomeService with a different implementation, the ViewModelService class must be modified.
- If SomeService has dependencies, they must also be configured by the ViewModelService class. In a large project with multiple classes depending on SomeService, the configuration code becomes scattered across the app.
- This implementation is difficult to unit test. The app should use a mock or stub SomeService class, which isn't possible with this approach.
Dependency injection addresses these problems through:
- The use of an interface or base class to abstract the dependency implementation.
- Registration of the dependency in a service container. ASP.NET Core provides a built-in service container, IServiceProvider. Services are typically registered in the app’s
Startup.ConfigureServices
method. - Injection of the service into the constructor of the class where it’s used. The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it’s no longer needed.
In the sample app, the ISomeService interface defines the WriteSomething method and this interface is implemented by a concrete type, SomeService:
The sample app registers the ISomeService service with the concrete type SomeService. The AddScoped method registers the service with a scoped lifetime, the lifetime of a single request.
By using the DI pattern, the controller:
- Doesn’t use the concrete type SomeService, only the ISomeService interface it implements. That makes it easy to change the implementation that the ViewModelService class uses without modifying the it.
- Doesn’t create an instance of SomeService, it's created by the DI container.
Service lifetimes
Services can be registered with one of the following lifetimes:
- Transient
- Scoped
- Singleton
Transient
Transient lifetime services are created each time they’re requested from the service container. This lifetime works best for lightweight, stateless services. Register transient services with AddTransient method.
Scoped
A scoped lifetime indicates that services are created once per client request (connection). Register scoped services with AddScoped method.
Singleton
As the name suggested , a singleton lifetime indicates that create and share a single instance of a service throughout the application’s lifetime.Register scoped services with AddSingleton method.
Let’s play more on DI
:-} Now we can create as many as service we want to, but the problem with this approach is that how many times we will create a class, we need to register it as a dependency. It would be great if we can automate this process. To overcome this problem, we have something called Reflection in C# language.
We can create three types from which we could identify how we need to register our service for its lifetime as mentioned below.
We can implement one of the above interfaces in our service type.
Now we can play with some reflection and pull our types on runtime which following the specific convention mentioned in the below snippet.
Now you don’t need to register your types manually. You just need to follow a specific convention. This is a very basic example I choose just to demonstrate how we can automate DI. You can write a more complex reflection to pull your types and register according. I hope now most of the aspects regarding DI are more clear to you. Thanks for bearing me for a couple of minutes. Happy learning.