Detailed explanation of how to use dependency injection in. NET Core console program

  • 2021-10-27 06:58:10
  • OfStack

Background introduction

Dependency Injection: Also known as dependency injection, or DI for short. In the previous development mode, layers and classes call each other through new1 instances of each other, which has a benefit in the development process, and can clearly know which specific implementation is used. As the software becomes larger and more complex, it is no longer appropriate to hold specific implementations with each other when it is necessary to change the implementation mode or rely on some interfaces of the third-party system. In order to cope with this situation, we should adopt contract programming: we rely on each other's stipulated contracts (interfaces), not on the specific implementation. The advantage of this is that the dependence on each other becomes very simple, also known as loose coupling. As for the mapping relationship between contract and concrete implementation, it will be determined by runtime when the program starts through configuration. This will use DI.

Dependency injection (Dependency Injection) is a design principle in object-oriented programming, which can be used to reduce the coupling between codes. In. NET Core MVC

We can use the service container IServiceCollection in the ConfigureService method of the Startup. cs file to register the mapping of the interface and its implementation classes.

For example, when we need to access the Http context, we need to configure the IHttpContextAccessor interface and its implementation class HttpContextAccessor


 public void ConfigureServices(IServiceCollection services)
 {
 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
 services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
 }

So how do we use dependency injection when we write a. NET Core console program?

Using built-in dependency injection

In. NET Core, the assembly used by the built-in dependency injection module is Microsoft.Extensions.DependencyInjection .

So if you want to use built-in dependency injection in your console program, you first need to use NUGET to add a Microsoft.Extensions.DependencyInjection A reference to the assembly.


PM> Install-Package Microsoft.Extensions.DependencyInjection

To illustrate how to use the built-in dependency injection module of. NET Core, we create the following two service interfaces.


 public interface IFooService
 {
 void DoThing(int number);
 }

 public interface IBarService
 {
 void DoSomeRealWork();
 }

Then we add two corresponding implementation classes for these two service interfaces


 public class BarService : IBarService
 {
 private readonly IFooService _fooService;
 public BarService(IFooService fooService)
 {
  _fooService = fooService;
 }

 public void DoSomeRealWork()
 {
  for (int i = 0; i < 10; i++)
  {
  _fooService.DoThing(i);
  }
 }
 }

 public class FooService : IFooService
 {
 private readonly ILogger<FooService> _logger;
 public FooService(ILoggerFactory loggerFactory)
 {
  _logger = loggerFactory.CreateLogger<FooService>();
 }

 public void DoThing(int number)
 {
  _logger.LogInformation($"Doing the thing {number}");
 }
 }

Code interpretation

The BarService class constructor relies on an implementation of the IFooService interface The FooService class constructor relies on an implementation of an ILoggerFactory interface In FooService, we output 1 Information level log

In the above implementation class code, we used the logging module built into. NET Core, so we also need to add the corresponding assembly Microsoft. Extensions. Logging. Console using NUGET


PM> Install-Package Microsoft.Extensions.Logging.Console

Finally, let's modify Program. cs with the following code


using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

 public class Program
 {
 public static void Main(string[] args)
 {
  //setup our DI
  var serviceProvider = new ServiceCollection()
  .AddLogging()
  .AddSingleton<IFooService, FooService>()
  .AddSingleton<IBarService, BarService>()
  .BuildServiceProvider();

  //configure console logging
  serviceProvider
  .GetService<ILoggerFactory>()
  .AddConsole(LogLevel.Debug);

  var logger = serviceProvider.GetService<ILoggerFactory>()
  .CreateLogger<Program>();
  logger.LogInformation("Starting application");

  //do the actual work here
  var bar = serviceProvider.GetService<IBarService>();
  bar.DoSomeRealWork();

  logger.LogInformation("All done!");

 }
 }

Code interpretation

Here we have manually instantiated an ServiceCollection class, which is IServiceCollection > Interface, which is a. NET Core built-in service container. Then we registered the IFooService interface implementation class FooService and the IBarService interface implementation class BarService in the service container. When we needed to get the corresponding implementation class of the interface class from the service container, we only needed to call the GetSerivce method of the service container class.

Final effect

Run the program, we expect the log, and output it correctly

info: DIInConsoleApp.Program[0]
Start application.
info: DIInConsoleApp.FooService[0]
Doing the thing 0
info: DIInConsoleApp.FooService[0]
Doing the thing 1
info: DIInConsoleApp.FooService[0]
Doing the thing 2
info: DIInConsoleApp.FooService[0]
Doing the thing 3
info: DIInConsoleApp.FooService[0]
Doing the thing 4
info: DIInConsoleApp.FooService[0]
Doing the thing 5
info: DIInConsoleApp.FooService[0]
Doing the thing 6
info: DIInConsoleApp.FooService[0]
Doing the thing 7
info: DIInConsoleApp.FooService[0]
Doing the thing 8
info: DIInConsoleApp.FooService[0]
Doing the thing 9
info: DIInConsoleApp.Program[0]
All done!

Using third-party dependency injection

In addition to using the built-in dependency injection module, we can also directly use a number of third-party dependency injection frameworks, such as Autofac, StructureMap.

Here we use StructureMap to replace the current built-in dependency injection framework.

First, we need to add assembly references.


PM> Install-Package StructureMap.Microsoft.DependencyInjection

Then we modify the Program. cs file with the following code


using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using StructureMap;
using System;

namespace DIInConsoleApp
{
 class Program
 {
 static void Main(string[] args)
 {
  var services = new ServiceCollection().AddLogging();

  var container = new Container();
  container.Configure(config =>
  {
  config.Scan(_ =>
  {
   _.AssemblyContainingType(typeof(Program));
   _.WithDefaultConventions();
  });

  config.Populate(services);
  });

  var serviceProvider = container.GetInstance<IServiceProvider>();

  serviceProvider.GetService<ILoggerFactory>().AddConsole(LogLevel.Debug);

  var logger = serviceProvider.GetService<ILoggerFactory>().CreateLogger<Program>();
  logger.LogInformation("Start application.");

  var bar = serviceProvider.GetService<IBarService>();
  bar.DoSomeRealWork();

  logger.LogInformation("All done!");
  Console.Read();
 }
 }
}

Code interpretation

Here we instantiate an StructureMap service container, Container, and configure the interface class and the automatic search of its implementation class in its Configure method. The interface class must begin with the letter "I", and the name of the implementation class differs from the interface class by only one letter "I", such as IFooService, FooService, IBarService and BarService The following code and the previous example are basically 1. Although it seems that there is a lot of code, in fact, this injection method using conventions is very powerful, which can save a lot of manually configured code.

Final effect

Run the program, code and the previous effect 1 sample

info: DIInConsoleApp.Program[0]
Start application.
info: DIInConsoleApp.FooService[0]
Doing the thing 0
info: DIInConsoleApp.FooService[0]
Doing the thing 1
info: DIInConsoleApp.FooService[0]
Doing the thing 2
info: DIInConsoleApp.FooService[0]
Doing the thing 3
info: DIInConsoleApp.FooService[0]
Doing the thing 4
info: DIInConsoleApp.FooService[0]
Doing the thing 5
info: DIInConsoleApp.FooService[0]
Doing the thing 6
info: DIInConsoleApp.FooService[0]
Doing the thing 7
info: DIInConsoleApp.FooService[0]
Doing the thing 8
info: DIInConsoleApp.FooService[0]
Doing the thing 9
info: DIInConsoleApp.Program[0]
All done!

This source code (local download)

Summarize


Related articles: