Dependency injection is native-available in .NET Core
DI implementation
interface we want to inject
public interface IDateTime
{
DateTime Now { get; }
}
interface’s implementation
public class SystemDateTime : IDateTime
{
public DateTime Now
{
get { return DateTime.Now; }
}
}
service we inject into
public class HomeController : Controller
{
private readonly IDateTime _dateTime;
public HomeController(IDateTime dateTime)
{
_dateTime = dateTime;
}
public IActionResult Index()
{
var serverTime = _dateTime.Now;
return Ok(serverTime);
}
}
Configuration: We have to register our DI services into startup.cs
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration
}
public void ConfigureServices(IServiceCollection services)
{
// add dependencies here
services.AddSingleton<IDateTime, SystemDateTime>();
}
}
Services lifetime types
- scoped: objects are the same for a given request, but differ across each new request (think of a shared class. A class that’s called in multiple other classes. Each parent-class would share the same child-class instance)
- transient: objects are always different. they’re created each time they’re called (each parent-class would’ve an unique child-class instance)
- singleton: objects are always the same for every request
(!) We have to be careful. If we put an object with a shorter lifetime inside a longer living object, the inner object would only be created once. (think a transient or scoped dependency inside a singleton). (!)
The other way around is OK. You can put a singleton dependency inside a transient or scoped with no problem.
Examples on when to use each one
- scoped: (created once per request) we may use this for a SQL connection. It will create and dispose the SQL connection per request.
- transient: (created each time they’re requested from the service container) For example, for an
HttpClient
service. We want this service to create a new HttpClient every time we send a request, so we don’t reuse the same old one. - singleton: normally used for a global single instance. For example, you if you have an image store service, you could have a service to load images from a given location and keep them in memory for future use.
Injection with FromServices
This enables injection directly into an action method without using constructor injection.
public IActionResult About([FromServices] IDateTime dateTime)
{
return Content($"current server time: {dateTime.Now}");
}
Reference(s)
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection?view=aspnetcore-8.0#action-injection-with-fromservices
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-8.0#service-lifetimes
https://stackoverflow.com/questions/67206763/when-to-use-following-transient-scoped-and-singleton