使用依赖注入时在 .NET Core Web API 中的另一个 class 中使用 class 及其功能

Using a class and its features in another class in .NET Core Web API when using dependency injection

我有一个这样的 class,我想在控制器正在使用的另一个 class 中使用它的方法:

public class CommunicationApi
{
    private readonly IConfiguration _configuration;
    
    private readonly ILogger _logger;
    private readonly MyAuthentication _myAuthentication;

    public myEmail MyMail { get; set; }
    public string[] Attachments { get; set; }
    public bool IsBodyHtml { get; set; }

    public CommunicationApi(ILogger<AdoExtract> logger, Func<string, myAuthentication> SAuth, IConfiguration configuration = null)
    {
        _configuration = configuration;
        _logger = logger;
        _myAuthentication = mAuth("ApiGatewayScope");
    }

    public async Task<int> SendMail()
    {
        //.....
    }
}

我正在尝试在另一个 class 中使用这个 class 和方法,就像这样

public class AdoExtract : IAdoExtract
{
    private readonly IConfiguration _configuration;       
    private readonly ILogger _logger;
    private readonly Communication _com;

    public AdoExtract(ILogger<AdoExtract> logger, IConfiguration configuration = null, CommunicationApi com = null)
    {
        _configuration = configuration;
        _logger = logger;
        _com = com;
    }

    public async Task<int> TestMail()
    { 
         _com  // here I am trying to set the properties of the above communication APIs such as MyEmail,Attachments
    }
}

我需要在另一个 class 的 TestMail 函数中设置 communicationAPI class 的属性。但是我没有得到任何我真正需要调用来发送电子邮件的属性或函数 SendMail()

startup.cs 我添加了 CommunicationAPI 这样的

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<CommunicationApi>();
}

我真的认为这不是正确的方法。请帮我解决这个问题。我对 DI 很陌生。

  1. 为您的 CommunicationApi 创建接口 class,您将在其中公开要执行的方法:
public interface ICommunication
{
    Task<int> SendMail();
}
  1. 具体实现这个接口class (CommunicationApi)
public class CommunicationApi : ICommunication
  1. 在 ConfigureServices 方法中配置依赖:
services.AddScoped<ICommunication, CommunicationApi>();
  1. 重写你的消费者class:
public class AdoExtract : IAdoExtract
{
    private readonly IConfiguration _configuration;       
    private readonly ILogger _logger;
    private readonly ICommunication _com;
    public AdoExtract(ILogger<AdoExtract> logger, IConfiguration configuration, 
    ICommunication com)
    {
        _configuration = configuration;
        _logger = logger;
        _com = com;
    }
    public async Task<int> TestMail()
    { 
       int result = await _com.SendMail();
    }
}

由于您希望 DI 将 CommunicationApi 注入 AdoExtract,您需要确保 DI 容器具有创建 CommunicationApi 实例所需的所有信息,即一个 ILogger<AdoExtract>、一个 Func<string, myAuthentication> 和一个 IConfiguration;否则无法调用 CommunicationApi 的构造函数。在您的情况下,最有可能缺少的是 Func。虽然您肯定可以通过为特定类型注册一个实例来注入它,但我怀疑这是一个好主意,因为 Func<> 不够具体。考虑创建一个包装它的接口,然后注册一个实例:

public interface IAuthenticationFactory {
    MyAuthentication AuthenticationForKey(string key);
}

ConfigureServices中注册这个接口的实现,然后注入它而不是Func,并在构造函数中调用AuthenticationForKey("ApiGatewayScope")

注意:传递一个完整的 IConfiguration 对象可以让接收方 class 访问比它需要的更多的信息。使用 Options pattern 来解决这个缺点。

您可以重构您的代码,创建一个单独的 class 包含所有属性。

       class ApiData
       {
           public myEmail MyMail { get; set; }
           public string[] Attachments { get; set; }
           public bool IsBodyHtml { get; set; }
       }

然后,您创建一个包含您的通信服务的所有方法的接口。

    public interface ICommunicationApiService
    {
        Task<int> SendMail();
        //...All your methods
    }

在那之后你的 Class CommunicationApi 应该实现那个接口

    public class CommunicationApiService :ICommunicationApiService
    {
        private readonly IConfiguration _configuration;
        private readonly ILogger _logger;
        private readonly MyAuthentication _myAuthentication;

        public CommunicationApi(ILogger<AdoExtract> logger, Func<string, 
           myAuthentication> SAuth, IConfiguration configuration = null)
        {
            _configuration = configuration;
            _logger = logger;
            _myAuthentication = mAuth("ApiGatewayScope");
        }

        public async Task<int> SendMail()
        {
           //.....Your implementation
        }

        //....
     }

注册服务后:

 public void ConfigureServices(IServiceCollection services)
 {      
  services.AddScoped<ICommunicationApiService,CommunicationApiService>();
 }

当你想使用你的服务时,你只需在构造函数中传递接口,在运行时服务将被解析。

public class AdoExtract : IAdoExtract
{
    private readonly IConfiguration _configuration;       
    private readonly ILogger _logger;

    private readonly ICommunicationApiService _communicationApiService;

    public AdoExtract(ILogger<AdoExtract> logger,
            IConfiguration configuration = null, 
            ICommunicationApiService _communicationApiService)
    {
        _configuration = configuration;
        _logger = logger;
        _communicationApiService = communicationApiService;
    }

    public async Task<int> TestMail()
   { 
     // here you create your ApiData object and then use your Api service ....
   }