Sample Example using Asp.net core
Recorded Video Link: https://www.youtube.com/watch?v=oVj1IHw8GLU
OverviewOfDI: https://github.com/sandeepmvn/DependencyInjectionRepository/blob/master/OverviewOfDI.txt
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.
Through IoC container, we can achieve
- Loosely coupled classes
- Managing lifetime of object
- Injects dependencies to the class
- Easy to change the implementation
- Test driven development (TDD)
In Asp.net core, IoC Container has built-in interfaces.
- IServiceProvider
- IServiceCollection
The following DI Lifecycle will be
- Register:-
- The Container must know which type of object/dependency should instantiate.
- In Asp.net core, services are registered using "IServiceCollection".
- this services are typically registered in the app's "Startup.ConfigureServices" method.
- Resolve:-
- When using IoC container, we don't create objects manually, Container does for us.
- In Asp.net core, the framework takes on the responsibility of creating an instance of the dependency with support of built-in container(IServiceProvider)
- Dispose:- The lifetime of object/dependecy will be taken care by IOC container only
There are basically two types of services in ASP.NET Core:
Framework Services: Services which are a part of ASP.NET Core framework such as IApplicationBuilder, IHostingEnvironment, ILoggerFactory etc.
Application Services: The services (custom types or classes) which you as a programmer create for your application.
Asp.Net Core MVC controller request dependencies explicitly via constructors 1. Constructor Injection 2. Method Injection (Action level) 3. Propery Injection (not supported) 4. View Injection
-
Constructor Injection: - Services are added as a constructor parameter and runtime resolve the service from the service container (IServiceCollection-- DiContainer). Servicesa are typically defined using non-concrete class (interfaces)
-
Method Injection : - Using [FromService] attribute enables injecting service directly into an action method without using controller injection
-
Property Injection Currently(Asp.net core) bulit-in IOC container doesn't support property injection.For this you might go for third-party built-in service containers (IOC).
-
View Injection Using [Inject] directive enables injecting service directly into view page without using controller or method injection
The built-in IoC container support three kinds of lifetime:
- Singleton:
- Singleton lifetime services(State service) are created the first time they're requested (or when ConfigureServices is run if you specify an instance there) and then every subsequent request will use the "same instance", throughout the application lifetime
- Core provides you bulit-in extension methods
- Add() (ServiceLifetime.Singleton)
- AddSingleton()
- Transient :
- Transient lifetime services are created each time they're requested. This lifetime works best for lightweight, "stateless services".
- Core provides you bulit-in extension methods
- Add() with (ServiceLifetime.Transient)
- AddTransient()
- Scoped :
- Scoped lifetime services are created once per request and will be shared in a single request.
- Core provides you bulit-in extension methods
- Add() with (ServiceLifetime.Scoped)
- AddScoped()
- AddDBContext()
In the sample example, "IMyDependency" service interface defines "WriteMessage" method
public interface IMyDependency
{
void WriteMessage(string message);
}
This interface is implemented by a concrete type, MyDependency:
public class MyDependency : IMyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage Message: {message}");
}
}
Now, Registers the "IMyDependency" service with the concrete type "MyDependency" (in startup.cs)
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.Add(new ServiceDescriptor(typeof(IMyDependency), new MyDependency()));
}
}
Here Add() method of "IServiceCollection" instance is used to register a service with an IoC container. The "ServiceDescriptor" is used to specify the type of service and concrete implementation. This will register our service in container with default as "Singleton"
Now, let's inject services with different life times
-
Singleton (Use case : when we need to create state service) :
services.Add(new ServiceDescriptor(typeof(IMyDependency), new MyDependency(),ServiceLifetime.Singleton));
-
Transient (Use case : when we need to create stateless service):
services.Add(new ServiceDescriptor(typeof(IMyDependency), new MyDependency(),ServiceLifetime.Transient));
-
Scoped (Use case : Database service):
services.Add(new ServiceDescriptor(typeof(IMyDependency), new MyDependency(),ServiceLifetime.Scoped));
We can also inject the services using bulit-in extension methods
-
Singleton
services.AddSingleton<IMyDependency, MyDependency>(); or services.AddSingleton(typeof(IMyDependency), typeof(MyDependency));
-
Transient
services.AddTransisent<IMyDependency, MyDependency>(); or services.AddTransient(typeof(IMyDependency), typeof(MyDependency));
-
Scoped
services.AddScoped<IMyDependency, MyDependency>(); or services.AddScoped(typeof(IMyDependency), typeof(MyDependency));
public class HomeController : Controller { private readonly IMyDependency _service;
public HomeController(IMyDependency service)
{
_service = service;
}
public IActionResult Index()
{
_service.WriteMessage("Constructor level injection")
return View();
}
}
public class HomeController : Controller
{
//Fromservice attribute
public IActionResult Index([FromService]IMyDependency service)
{
service.WriteMessage("Action level injection")
return View();
}
}
public class HomeController : Controller {
public IActionResult Index()
{
return View();
}
}
In Index.cshtml
@{ ViewData["Title"] = "Home Page"; }
//using Inject directive
@inject IMyDependency service
//code block
@{
service.WriteMessage("View level Injection");
}
public class HomeController : Controller {
public IActionResult Index()
{
var services = this.HttpContext.RequestServices;
var dependencyservice = (IMyDependency)services.GetService(typeof(IMyDependency));
dependencyservice.WriteMessage("without injection, accessing dependent services");
return View();
}
}