asp. Net core

Time:2022-5-14

Generally, when using injection, one service interface corresponds to one implementation class, and the injection method is constructor injection. However, if there are multiple classes implementing the same interface, different implementation classes need to be selected according to the actual situation.

For example, both myemailservice and emailservice in the following code implement iemailservice interface:

    public class MyEmailService : IEmailService
    {
        public string Send(string Email)
        {
            return "My" + Email;
        }
    }

    public class EmailService : IEmailService
    {
        public string Send(string Email)
        {
            return Email;
        }
    }

In this case, you need to choose different service implementations according to different situations.

Asp. Net core comes with its own container. At the same time, you can use Autofac to replace the default container. The following are two ways to register and implement the service with the same name.

1. Use Net core’s own container

Supplement: corresponding to the implementation of multiple services, if a single service is obtained, the implementation of the last service is obtained by replacement.

https://stackoverflow.com/questions/48185894/when-to-use-tryaddsingleton-or-addsingleton, this article explains the replacement and the difference between tryaddsingleton and addsingleton.

 

If the built-in container is adopted, because our iemailservice has multiple implementation classes at this time, we need to inject iserviceprovider, and then obtain multiple services through the getservices complex version of iserviceprovider. At this time, multiple implementation services can be called in sequence. If we need to distinguish one of them, we can distinguish it by type.

[Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        private readonly IEnumerable emailService;

        private readonly ILogger logger;

        /// 
        ///Inject iserviceprovider to get service
        /// 
        /// 
        /// 
        public ValuesController(IServiceProvider serviceProvider, ILogger logger)
        {
            var service = serviceProvider. GetServices(); // Get service
            this.emailService = service;
            this.logger = logger;
        }

        [HttpGet]
        public IActionResult Send(string email)
        {
            //Can traverse services
            foreach (var emailService in emailService)
            {
                if(emailService.GetType() == typeof(First_EmailService))
                { 
                    //Console output call log
                    logger.LogInformation(emailService.Send(email));
                }
            }
            return Ok();
        }
    }

2. Implementation in Autofac

If you need to parse different services in Autofac, you need to use the named implementation. First, you need to get the container of Autofac, that is, icontainer instance. There are two kinds of locations to get:

(1) Get it in the registration module class in configurecontainer. The relevant codes are as follows:

public class ConfigureAutofac : Autofac.Module
    {
        private static IContainer _container;

        protected override void Load(ContainerBuilder containerBuilder)
        {
            //Register two different named services
            containerBuilder.RegisterType().Named("one");
            containerBuilder.RegisterType().Named("two");

            //Need to get container in callback
            containerBuilder.RegisterBuildCallback(container =>
            {
                _container = (IContainer)container;
                var one =  _container.ResolveNamed("two");
                one.Send("one");
            });
        }
    }

(2) The above services are implemented in the module configuration of Autofac or in startup. You need to call the getautofacroot method of Autofac

/// 
        ///Configureservices injects the default container, Autofac will take over the default container, and then execute configurecontainer
        /// 
        /// 
        public void ConfigureContainer(ContainerBuilder builder)
        {
            builder.RegisterType().As();
        }
 
        //Register root container
        public ILifetimeScope AutofacContainer { get; private set; }
 
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
 
            var serviceName = this.AutofacContainer.Resolve();
            serviceName.ShowCode();
 
            //...
        }

(3) If you need to implement service calls with different names in the controller, you need to inject the iaapplicationbuilder interface into the controller, but the direct injection will report an unresolved service error, which needs to be manually configured in configureservices

services.AddSingleton();

After that, it can be injected into the controller normally

[Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        private readonly IApplicationBuilder app;
        private readonly ILogger logger;
        public ILifetimeScope AutofacContainer { get; private set; }


        public ValuesController(IApplicationBuilder app, ILogger logger)
        {
            this.app = app;
            this.logger = logger;
        }

        [HttpGet]
        public IActionResult Send(string email)
        {
            this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();

            var serviceName = this.AutofacContainer.ResolveNamed("one");

            logger.LogInformation(serviceName.Send(string.Empty));

            return Ok();
        }
    }

(4) Two other methods can also be used for the registration of controllers or other classes, namely

a. Obtain the Autofac root container from iserviceprovider and then obtain the instance;

b. Use the ilifetimescope of Autofac to obtain the instance;

The method of using iserviceprovider is similar to the third method above. It is to obtain the root container of Autofac, and then analyze it according to the name. The built-in ilifetimescope can be used as method injection to obtain the container of Autofac inside the method.

/// 
        ///Ilifetimescope -- Method injection
        /// 
        /// 
        /// 
        /// 
        [HttpGet]
        public IActionResult DiTest([FromServices]ILifetimeScope lifetime,string name)
        {
            var one = lifetime.ResolveNamed("one");

            //Where service is the iserviceprovider interface injected in the constructor
            var two = service.GetAutofacRoot().ResolveNamed("two");

            return Ok(one.Send(name));
        }

 

 

reference resources: https://blog.csdn.net/hahahzzzzz/article/details/118684998

reference resources: https://blog.csdn.net/puzi0315/article/details/118578868