.NET Core provides built-in Dependency Injection (DI) Framework. ASP.NET Core utilizes it. ASP.NET Core registers Controllers & Views with DI Framework for us. But we need to register our services (classes) with DI Framework.
Register Services (classes) with DI Framework
We need to register our Non-Controller classes with the DI Framework if,
- We want to inject any dependency to these classes Or
- We want to inject our classes as a dependency on other classes.
For example, we have IEmailSender interface and EmailSender class (one implementation of interface). We want to use IEmailSender (instead of EmailSender) in our consumer classes. So, we'll tell DI Framework that if a class asks for IEmailSender dependency, create an instance of EmailSender and inject that.
We do this in Startup.ConfigureServices
- services.AddScoped<IEmailSender, EmailSender>();
Also, we need to register Consumer classes (In which we want to inject dependencies). DI Framework will create an instance of consumer classes and will inject the 'required' dependencies. For example, we have a consumer class (TestManager) which depends on some services, such as - IEmailSender.
So we'll register TestManager.
- services.AddScoped<TestManager>();
Note
You may use AddTransient or AddSingleton according to your need & logic.
Injecting Services in Controller or Non-Controller classes
Now, wherever we want to use any service, we'll simply create a variable of that type in the constructor (i.e. Construction injection). In the following example, we want to use Logger, Configuration, and EmailSender in one of our controllers.
- public UserController(ILogger<UserController> logger, IConfiguration configuration, IEmailSender emailSender)
- {
- _logger = logger;
- _configuration = configuration;
- _emailSender = emailSender;
- }
Note
It is not a recommended practice to inject IConfiguration to get configurations.
Using Services Through DI In Action Methods
We may need a specific service only in specific Action/s. If we want to inject a service directly into the action method (instead of injecting through the constructor), we can use [FromServices] attribute.
- public IActionResult About([FromServices] IEmailSender emailSender)
- {
- return View();
- }
Using Services Through DI in Views
Ideally, we should be passing data to views from controllers but if ever we need to use any service in Views, we may inject that in Views. We do that using the @inject helper.
Here we are injecting EmailSender object in View file and then we may use this 'emailSender' object in view to access its members.
- @inject IEmailSender emailSender
Creating Instance of a Consumer Class Manually In Controller
In certain situations, we may need to create an instance of the consumer class (a class which is dependent on other services). In such situations, we should use DI Framework to create the instance of the consumer class. Controller provides us HttpContext which contains 'RequestServices' (of type IServicesProvider) property.
Here, we are creating an instance of TestManager class in Controller.
- var t =(TestManager) this.HttpContext.RequestServices.GetService(typeof(TestManager));
By adding Microsoft.Extensions.DependencyInjection namespace, we get a generic version of GetService.
- var t = this.HttpContext.RequestServices.GetService<TestManager>();
Creating Instance of a Consumer Class Manually In Any class
To create an instance of the consumer class, we need IServicesProvider. Controller class provides us this by default. But we may also inject IServicesProvider in the Controller or non-controller classes.
- public UserController(IServiceProvider serviceProvider)
- {
- _serviceProvider = serviceProvider;
- }
And then, we may use GetService Method to create instance.
- var t2= (TestManager) _serviceProvider.GetService(typeof(TestManager));
By adding Microsoft.Extensions.DependencyInjection namespace, we get a generic version of GetService.
- var t4 = _serviceProvider.GetService<TestManager>();
- var t3 = _serviceProvider.GetRequiredService<TestManager>();
Conclusion
ASP.NET Core heavily depends on Dependency Injection. We'll not be able to write better applications without understanding the basics of this framework and adopting it.