This article will cover in details dependency injection in ASP.NET Core 3.1. ASP.NET Core is designed from the ground up to support the dependency injection design pattern.
Dependency injection in ASP.NET Core provides a technique to create applications that are loosely coupled. ASP.NET Core allows us to inject dependent objects either through constructors or methods. Based on the environment in which the application is running different objects can be injected.
What is Dependency Injection?
Dependency injection in ASP.NET Core is used to achieve loose coupling in application between client objects and their dependencies. Instead of directly instantiating objects of classes and using them rather Interfaces are used and objects are provided to the class in some way either through a constructor or through some method.
The class will depend on an interface rather than a concrete implementation of dependencies. This makes our code loosely coupled as we can inject any concrete object as far as it implements the required interface.
ASP.NET Core comes with a built-in container (IServiceProvider) that supports constructor injection by default and the framework itself provides some services through dependency injection.
Here is a great article by Martin Fowler on Dependency Injection
Why Dependency Injection in ASP.NET Core?
- Improves code readability by keeping it clean so easier to maintain it.
- Application is loosely coupled which improves flexibility
- Increases code testing ability with different mock implementations of services.
- Supports extendable class structure
Implementation of Dependency Injection in ASP.NET Core
There are two types of services in ASP.NET Core
- Framework provided services – These services are part of the ASP.NET Core framework
- Custom Services – These are add-on services created by developers
Registering framework provided services
The below code shows how to register a framework defined service (Memory Caching Service) in ConfigureServices() method of a startup.cs
public class Startup { // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddMemoryCache(); } //Remaining code was removed }
Registering your own services
You can even register your own service and make it available for dependency injection into controllers, middlewares & views
First, you need to define the service using an interface as shown below
public interface ILogger { void Log(string message); void Log(string message, Exception ex); } public class LogToFile : ILogger { public void Log(string message) { //Log Message to File } public void Log(string message, Exception ex) { //Log Message & Exception to File } } public class LogToDB : ILogger { public void Log(string message) { //Log Message to Database } public void Log(string message, Exception ex) { //Log Message & Exception to Database } }
Service Lifetime
Before we talk about how to register your service in the startup.cs file we need to understand the significance of Service Lifetime while registering a service. Lifetime decides whether the instance of a service being injected is a new instance to that component or it same signal instance which is being used everywhere in the application. While registering for a service you need to choose the lifetime for each service.
Transient – Each time a new object is created for dependency injection i.e. each component will have its unique instance. This is the option used for lightweight & stateless services.
services.AddTransient<ILogger, LogToFile>();
Scoped – This means that it is created once for each request i.e. a new object will be created for each new request.
services.AddScoped<ILogger, LogToFile>();
Singleton – One single component will be created for the lifetime of the application. This single instance is shared across all components and all requests.
services.AddSingleton<ILogger, LogToFile>();
Registering Services in the startup.cs
You need to register the required services in the ConfigureServices() method in the startup.cs file
public class Startup { // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddMemoryCache(); services.AddTransient<ILogger, LogToDB>(); } //Remaining code has been removed }
Once service is registered it can be injected into other components
Injecting services (framework/custom) into Middleware
Below is the code sample for the injection of service into middleware. Either it can be injected through the constructor or through the invoke method.
public class ExceptionMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; private readonly IMemoryCache _cache; public ExceptionMiddleware(RequestDelegate next, ILogger logger, IMemoryCache cache) { _next = next; _logger = logger; _cache = cache; } public Task Invoke(HttpContext httpContext, ILogger logger, IMemoryCache cache) { return _next(httpContext); } }
Injecting services (framework/custom) into the Controller
Below is the code sample for the injection of service into the controller. Either it can be injected through the constructor or through the action method.
public class HomeController : Controller { private readonly ILogger _logger; private readonly IMemoryCache _cache; public HomeController(ILogger logger, IMemoryCache cache) { _logger = logger; _cache = cache; } public IActionResult Index([FromServices] ILogger logger, [FromServices] IMemoryCache cache) { return View(); } }
Request Services Manually
Instead of using dependency injection to inject services, components can even manually request services. The below code shows how to manually request service using the HttpContext object.
var services = this.HttpContext.RequestServices; var log = (ILogger)services.GetService(typeof(ILogger));
Summary
Dependency injection in ASP.NET Core allows us to develop loosely coupled applications. Dependency injection in ASP.NET Core is supported and also it is simple and easy to implement. Framework provided services or your own custom services can be used for dependency injection.
You can inject components using dependency injection into the middleware pipeline, controllers, view, etc. Service lifetime can be used to control the scope of the service.
References: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1
You can also check my other Article on Microsoft Azure Storage – https://procodeguide.com/programming/azure-storage/
In your example you have showed 2 classes implementing the same interface, but u have used only one. How can we use both of the classes
Thanks.