• asp.net Core中的同名服务注册


    通常情况下,在使用注入时一个服务接口对应一个实现类,注入方式采用构造函数注入即可,但如果存在多个类实现同一个接口的情况下,则需要根据实际情况来选择不同的实现类。

    如以下代码中的MyEmailService和EmailService都实现了IEmailService接口:

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

    在这种情况,就需要根据不同的情况来选择不同的服务实现了。

    Asp.Net Core中自带了容器,同时也可以使用AutoFac替换掉默认的容器,以下为两种方式同名服务的注册实现。

    1、使用.net Core自带容器

    补:对应多个服务的实现,如果获取单个服务,是以替换方式获得最后一个服务的实现。

    https://stackoverflow.com/questions/48185894/when-to-use-tryaddsingleton-or-addsingleton,这篇文章有关于替换的解释,同时还有关于TryAddSingleton和AddSingleton的区别。

    如果采用自带容器,因为此时我们的IEmailService有多个实现类,因此需要注入IServiceProvider,然后通过IServiceProvider的GetServices复数版本来获取多个服务,此时可以顺序调用多个实现服务,如果需要区别其中的某一个服务,可以通过type加以区分。

        [Route("api/[controller]")]
        [ApiController]
        public class ValuesController : ControllerBase
        {
            private readonly IEnumerable<IEmailService> emailService;
    
            private readonly ILogger<ValuesController> logger;
    
            /// <summary>
            /// 注入IServiceProvider获取服务
            /// </summary>
            /// <param name="serviceProvider"></param>
            /// <param name="logger"></param>
            public ValuesController(IServiceProvider serviceProvider, ILogger<ValuesController> logger)
            {
                var service = serviceProvider.GetServices<IEmailService>(); //获取服务
                this.emailService = service;
                this.logger = logger;
            }
    
            [HttpGet]
            public IActionResult Send(string email)
            {
                //可以遍历服务
                foreach (var emailService in emailService)
                {
                    if(emailService.GetType() == typeof(First_EmailService))
                    { 
                        //控制台输出调用日志
                        logger.LogInformation(emailService.Send(email));
                    }
                }
                return Ok();
            }
        }

    2、AutoFac中的实现

    如果需要在Autofac中解析不同的服务,需要用到Named实现。首先,需要获取Autofac的容器,即IContainer实例。获取的位置有两种:

    (1)在ConfigureContainer中的注册模块类中进行获取,相关代码如下:

        public class ConfigureAutofac : Autofac.Module
        {
            private static IContainer _container;
    
            protected override void Load(ContainerBuilder containerBuilder)
            {
                //注册两个不同命名的服务
                containerBuilder.RegisterType<EmailService>().Named<IEmailService>("one");
                containerBuilder.RegisterType<MyEmailService>().Named<IEmailService>("two");
    
                //需要在回调用获取容器
                containerBuilder.RegisterBuildCallback(container =>
                {
                    _container = (IContainer)container;
                    var one =  _container.ResolveNamed<IEmailService>("two");
                    one.Send("one");
                });
            }
        }

    (2)上述服务是Autofac的模块配置中实现,也可以在Startup中实现,需要调用Autofac的GetAutofacRoot方法

            /// <summary>
            /// ConfigureServices将默认的容器注入进去,Autofac会接替默认的,然后执行ConfigureContainer
            /// </summary>
            /// <param name="builder"></param>
            public void ConfigureContainer(ContainerBuilder builder)
            {
                builder.RegisterType<MyService>().As<IMyService>();
            }
     
            //注册根容器
            public ILifetimeScope AutofacContainer { get; private set; }
     
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
     
                var serviceName = this.AutofacContainer.Resolve<IMyService>();
                serviceName.ShowCode();
     
                //...
            }

    (3)如果需要在控制器中实现不同名称的服务调用,则需要在控制器中注入IApplicationBuilder接口,但直接注入会报未解析服务的错误,需要手动在ConfigureServices中配置一下

    services.AddSingleton<IApplicationBuilder, ApplicationBuilder>();

    之后就可以在控制器中正常注入了

        [Route("api/[controller]")]
        [ApiController]
        public class ValuesController : ControllerBase
        {
            private readonly IApplicationBuilder app;
            private readonly ILogger<ValuesController> logger;
            public ILifetimeScope AutofacContainer { get; private set; }
    
    
            public ValuesController(IApplicationBuilder app, ILogger<ValuesController> logger)
            {
                this.app = app;
                this.logger = logger;
            }
    
            [HttpGet]
            public IActionResult Send(string email)
            {
                this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
    
                var serviceName = this.AutofacContainer.ResolveNamed<IEmailService>("one");
    
                logger.LogInformation(serviceName.Send(string.Empty));
    
                return Ok();
            }
        }

    (4)在控制器或其他类的注册,还可以使用另外两种方法,分别是

    a、 IServiceProvider里获取AutoFac根容器再进行获取实例;

    b、使用AutoFac自带的ILifetimeScope获取实例;

    其中使用IServiceProvider方式和上面第3种类似,都是取得Autofac的根容器,然后再根据命名进行解析,使用自带的ILifetimeScope可以做为方法注入,在方法内部获取Autofac的容器。

            /// <summary>
            /// ILifetimeScope——方法注入
            /// </summary>
            /// <param name="lifetime"></param>
            /// <param name="name"></param>
            /// <returns></returns>
            [HttpGet]
            public IActionResult DiTest([FromServices]ILifetimeScope lifetime,string name)
            {
                var one = lifetime.ResolveNamed<IEmailService>("one");
    
                //其中service为在构造函数中注入的IServiceProvider接口
                var two = service.GetAutofacRoot().ResolveNamed<IEmailService>("two");
    
                return Ok(one.Send(name));
            }

    参考:https://blog.csdn.net/hahahzzzzz/article/details/118684998

    参考:https://blog.csdn.net/puzi0315/article/details/118578868

  • 相关阅读:
    12 go实现几中基本排序算法
    5 控制语句
    9 函数
    4. 常量与运算符
    AI
    AI
    AI
    AI
    ML
    ML
  • 原文地址:https://www.cnblogs.com/superfeeling/p/16027474.html
Copyright © 2020-2023  润新知