How to resolve dependencies in ASP.NET Core

Explore three different ways to resolve dependencies in ASP.NET Core 6, using constructor injection, action method injection, or IServiceProvider instances.

How to resolve dependencies in ASP.NET Core
Thinkstock

Dependency injection is a technique that allows you to inject the dependent objects of a particular class rather than create those instances directly. Using dependency injection enhances testability and maintenance by facilitating loose coupling. Additionally, dependency injection allows you to modify your implementations without having to change the dependent types that rely on them.

Dependency injection is a first-class citizen in ASP.NET Core. The built-in dependency injection provider in ASP.NET Core is not as feature-rich as IoC (inversion of control) containers such as StructureMap and Ninject, but it is fast, easy to configure, and easy to use. You can inject both framework services and application services in ASP.NET Core.

This article talks about the various ways in which you can resolve dependencies in ASP.NET Core.

To work with the code examples provided in this article, you should have Visual Studio 2022 installed in your system. If you don’t already have a copy, you can download Visual Studio 2022 here.

Create an ASP.NET Core project in Visual Studio 2022

First off, let’s create an ASP.NET Core project in Visual Studio 2022. Following these steps will create a new ASP.NET Core Web API 6 project in Visual Studio 2022:

  1. Launch the Visual Studio 2022 IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “ASP.NET Core Web API” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window, specify the name and location for the new project.
  6. Optionally check the “Place solution and project in the same directory” check box, depending on your preferences.
  7. Click Next.
  8. In the “Additional Information” window shown next, select .NET 6.0 as the target framework from the drop-down list at the top. Leave the “Authentication Type” as “None” (default).
  9. Ensure that the check boxes “Enable Docker,” “Configure for HTTPS,” and “Enable Open API Support” are unchecked as we won’t be using any of those features here. You can optionally uncheck the “Use controllers (uncheck to use minimal APIs)” check box as well because we’ll be creating our own controller.
  10. Click Create.

This will create a new ASP.NET Core 6 Web API project in Visual Studio 2022. We’ll use this project to illustrate resolving dependencies in the subsequent sections of this article.

Resolve dependencies using constructor injection

Now create the following interface:

    public interface ICustomFileLogger
    {
        public string Text { get; set; }
        public void Log(string message);
    }

For the sake of simplicity, this is a minimal representation. The CustomFileLogger class implements the ICustomFileLogger interface as shown in the code snippet given below.

public class CustomFileLogger : ICustomFileLogger
{
   public string Text { get; set; }
   public void Log(string message)
   {
      //Write your own implementation here
   }
}

You can register an instance of type ICustomFileLogger as a scoped service in the ConfigureServices method if you’re using ASP.NET 5, or in the Program.cs file if you’re using ASP.NET 6.

services.AddScoped<ICustomFileLogger, CustomFileLogger>();

Next, create an API controller named DefaultController and enter the following code:

    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {
        private ICustomFileLogger _logger;
        public DefaultController(ICustomFileLogger logger)
        {
            _logger = logger;
            if(string.IsNullOrEmpty(_logger.Text))
                _logger.Text = DateTime.UtcNow.ToString();
        }
        [HttpGet]
        public string Get()
        {
            return "Hello World!";
        }
    }

Note how constructor injection has been used here. The constructor of the DefaultController class accepts an instance of type ICustomFileLogger as a parameter.

Resolve dependencies using action method injection

You should use constructor injection whenever you will need to use the injected instance in multiple methods. If you need to use the instance in a particular action method only, it is better to inject the instance in the action method rather than use constructor injection.

The following code snippet illustrates how action method injection can be achieved.

[HttpPost("Log")]
public IActionResult Log([FromServices] ICustomFileLogger customFileLogger)
{
   //Write your code here
    return Ok();
}

You might often need to inject many different services in your controller. If you’re using constructor injection, you would then have to specify several parameters in the constructor. A better solution to this is to use IServiceProvider.

Resolve dependencies using IServiceProvider

You can use the IServiceCollection interface to create a dependency injection container. Once the container has been created, the IServiceCollection instance is composed into an IServiceProvider instance. You can use this instance to resolve services. 

You can inject an instance of type IServiceProvider into any method of a class. You can also take advantage of the ApplicationServices property of the IApplicationBuilder interface and the RequestServices property of the HttpContext class to retrieve an IServiceProvider instance.

The following code snippet illustrates how you can inject an instance of type IServiceProvider.

public class DefaultController : Controller
{
    private IServiceProvider _provider;
    public DefaultController(IServiceProvider provider)
    {
        _provider = provider;
    }
}

You can use the following code snippet in your action methods to retrieve any of the service instances you need.

ICustomFileLogger logger = (ICustomFileLogger)_provider.GetService(typeof(ICustomFileLogger));

Note how the GetService method of IServiceProvider is used to retrieve the service instance.

You can use the RequestServices property of the HttpContext class to retrieve an instance of type IServiceProvider and then use this instance to call the GetService method. The following code shows how this can be done.

ICustomFileLogger logger = (ICustomFileLogger)HttpContext.RequestServices.GetService(typeof(ICustomFileLogger));

Dependency injection is an approach that enhances code maintenance and testability by facilitating loose coupling. You can use the built-in dependency injection support in ASP.NET Core to create applications that are modular, lean, and clean, as well as easier to maintain and test.

Copyright © 2021 IDG Communications, Inc.

How to choose a low-code development platform