• NetCore自带的IOC依赖注入如何实现一个接口多个实现类的注入


    提示:一般情况下我们都是使用一个接口一个实现类,但是有一些情况,我们为了实现多态,我们会定义一个接口,多个实现类。这种情况我们在NetCore自带的依赖注入容器中,我们应该怎么来实现呢?

    目录

    前言

    一、什么是依赖注入?

    二、使用步骤

    1.首先我们写一个扩展服务来批量注入我们的服务

    2.默认实现服务TenantServiceBase

    3.编写用户扩展服务

    4.服务的使用

    总结



    前言

    一般情况下我们都是使用一个接口一个实现类,但是有一些情况,我们为了实现多态,我们会定义一个接口,多个实现类。这种情况我们在NetCore自带的依赖注入容器中,我们应该怎么来实现呢?

    一、什么是依赖注入?

    依赖注入(Dependency Injection),是这样一个过程:由于某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点。在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境或专门组件负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。

    二、使用步骤

    1.首先我们写一个扩展服务来批量注入我们的服务

    代码如下(示例):

    1. using JuCheap.WebApi.Common;
    2. using JuCheap.WebApi.TenantCustomServices;
    3. using JuCheap.WebApi.TenantFactory;
    4. using JuCheap.WebApi.TenantServices;
    5. using JuCheap.WebApi.Utils;
    6. using Microsoft.Extensions.DependencyInjection;
    7. using System.Linq;
    8. using System.Reflection;
    9. namespace JuCheap.WebApi
    10. {
    11. /// <summary>
    12. /// 模块初始化
    13. /// </summary>
    14. public static class JuCheapServiceRegistor
    15. {
    16. public static void AddJuCheapService(this IServiceCollection services)
    17. {
    18. //基础服务注册
    19. services.AddScoped<ITenantFactoryService, TenantFactoryService>();
    20. services.AddScoped<IRedisService, RedisService>();
    21. services.AddScoped<ITenantServiceBase, TenantServiceBase>();
    22. //批量注入租户级自定义服务
    23. var serviceRegistrations = typeof(TenantServiceBase).Assembly.GetTypes()
    24. .Where(type => type.Namespace != null
    25. && type.Namespace.StartsWith("JuCheap.WebApi.TenantCustomServices")
    26. && type.GetCustomAttributes<TenantAttribute>().Any(x => x.TenantIds != null && x.TenantIds.Any()))
    27. .Select(type => new { Implementation = type })
    28. .ToList();
    29. foreach (var service in serviceRegistrations)
    30. {
    31. services.AddScoped(service.Implementation);
    32. }
    33. }
    34. }
    35. }

    2.默认实现服务TenantServiceBase

    代码如下(示例):

    1. using JuCheap.Common;
    2. using JuCheap.Models;
    3. using JuCheap.TenantServices;
    4. using JuCheap.Utils;
    5. namespace JuCheap.TenantCustomServices
    6. {
    7. /// <summary>
    8. /// 租户默认服务
    9. /// </summary>
    10. public class TenantServiceBase : ITenantServiceBase
    11. {
    12. public virtual string GetDefaultParam(int tenantId)
    13. {
    14. return $"{tenantId}-test";
    15. }
    16. }
    17. /// <summary>
    18. /// 租户默认服务接口
    19. /// </summary>
    20. public interface ITenantServiceBase
    21. {
    22. string GetDefaultParam(int tenantId);
    23. }
    24. }

    默认服务实现了一个获取默认参数的接口,但是我们不同的用户,获取的参数有可能不一样,有可能做过定制开发等等。

    3.编写用户扩展服务

    1. using JuCheap.Common;
    2. using JuCheap.Models;
    3. using JuCheap.TenantServices;
    4. using JuCheap.Utils;
    5. namespace JuCheap.TenantCustomServices
    6. {
    7. /// <summary>
    8. /// 用户扩展服务
    9. /// </summary>
    10. [Tenant(123456)]
    11. public class TenantService123456 : TenantServiceBase
    12. {
    13. public override string GetDefaultParam(int tenantId)
    14. {
    15. return $"{tenantId}-custom-123456";
    16. }
    17. }
    18. }

    4.服务的使用

    默认服务,我们可以通过直接注入ITenantServiceBase接口,就可以使用了,但是我们做过用户扩展服务的,应该怎么使用?我们需要一个工厂的服务接口,如下:

    1. using JuCheap.Common;
    2. using JuCheap.TenantServices;
    3. using Microsoft.Extensions.DependencyInjection;
    4. using System;
    5. using System.Linq;
    6. using System.Reflection;
    7. namespace JuCheap.TenantFactory
    8. {
    9. /// <summary>
    10. /// 租户服务获取工厂构造器
    11. /// </summary>
    12. public interface ITenantFactoryService
    13. {
    14. /// <summary>
    15. /// 获取租户服务,如果没有自定义服务,则返回默认的TenantBaseService服务
    16. /// </summary>
    17. /// <param name="tenantId">租户Id</param>
    18. /// <returns></returns>
    19. ITenantServiceBase GetTenantService(int tenantId);
    20. }
    21. /// <summary>
    22. /// 用户服务获取工厂构造器
    23. /// </summary>
    24. public class TenantFactoryService : ITenantFactoryService
    25. {
    26. private readonly IServiceProvider _serviceProvider;
    27. public TenantFactoryService(IServiceProvider serviceProvider)
    28. {
    29. _serviceProvider = serviceProvider;
    30. }
    31. /// <summary>
    32. /// 获取租户服务,如果没有自定义服务,则返回默认的TenantBaseService服务
    33. /// </summary>
    34. /// <param name="tenantId">租户Id</param>
    35. /// <returns></returns>
    36. public ITenantServiceBase GetTenantService(int tenantId)
    37. {
    38. var serviceRegistrations = typeof(TenantServiceBase).Assembly.GetTypes()
    39. .Where(type => type.Namespace != null
    40. && type.Namespace.StartsWith("JuCheap.TenantCustomServices")
    41. && type.GetCustomAttributes<TenantAttribute>().Any(x => x.TenantIds != null && x.TenantIds.Contains(tenantId)))
    42. .ToList();
    43. if (serviceRegistrations.Any())
    44. {
    45. if (serviceRegistrations.Count > 1)
    46. {
    47. throw new Exception($"{tenantId}的租户扩展服务找到多个实现类,请修改");
    48. }
    49. return _serviceProvider.GetRequiredService(serviceRegistrations.First()) as ITenantServiceBase;
    50. }
    51. //没有找到直接返回默认租户服务
    52. return _serviceProvider.GetRequiredService<ITenantServiceBase>();
    53. }
    54. }
    55. }

    当我们的用户有扩展服务的是否,我们使用工厂服务接口来获取扩展服务,如下:

    1. using JuCheap.Models;
    2. using JuCheap.TenantFactory;
    3. using Microsoft.AspNetCore.Mvc;
    4. namespace JuCheap.Controllers
    5. {
    6. /// <summary>
    7. /// 账号绑定Api
    8. /// </summary>
    9. [Route("api/[controller]/[action]")]
    10. [ApiController]
    11. public class BindAccountController : ControllerBase
    12. {
    13. private readonly ITenantFactoryService _tenantFactoryService;
    14. public BindAccountController(ITenantFactoryService tenantFactoryService)
    15. {
    16. _tenantFactoryService = tenantFactoryService;
    17. }
    18. /// <summary>
    19. /// 执行绑定验证
    20. /// </summary>
    21. [HttpPost]
    22. public IActionResult Bind([FromBody] BindRequestDTO requestDTO)
    23. {
    24. var tenantService = _tenantFactoryService.GetTenantService(User.TenantId);
    25. tenantService.BindAccount(requestDTO);
    26. return Ok(true);
    27. }
    28. }
    29. }


    总结

    netcore已经为我们提供了丰富多样的服务注入方式,类似上面的注入方式,我们也可以提供一个Func<int, ITenantServiceBase>的函数来实现,欢迎大家一起讨论。

  • 相关阅读:
    春秋云境CVE-2018-20604
    C++ —— 引用
    k8s部署
    C++——vector
    python 装饰器使用,打印函数调用层级_1
    kubernetes安装教程-完整版本
    华为认证 | 这门HCIA认证正式发布!
    华为od德科面试数据算法解析 2022-6-1 IP地址转换成整数
    离散数学第一章知识点复习
    乐划锁屏插画大赏热度持续,进一步促进价值内容的创造与传播
  • 原文地址:https://blog.csdn.net/allenwdj/article/details/125636152