1

I have a class like this which I would like to use its methods in another class which is being used by the controller:

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()
    {
        //.....
    }
}

I am trying to use this class and method in another class like this

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
    }
}

I need to set the properties of the communicationAPI class in the TestMail function of the other class. But I am not getting any of the properties or function SendMail() which I really need to call to send email.

In the startup.cs I have added the CommunicationAPI like this

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

Which I really believe its not the correct way. Please help me to solve this. I am pretty new to DI.

3 Answers 3

2

You can refactor your code, in way that you create a sperate class containing all the properties.

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

Then, you create an interface containing all methods of your communication service.

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

After that your Class CommunicationApi should implement that interface

    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
        }

        //....
     }

After that you register your Service:

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

When you want to use your service you only pass the interface in the constructor and at the runtime the service will be resolved.

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 ....
   }
Sign up to request clarification or add additional context in comments.

2 Comments

Sorry one question... So the API Data object in Test Mail, is it passing to the sendmail as function parameter?? or anyway to send it as that CommunicationApiService properties?
You can pass the ApiData as a parameter to the sendMail method. Thus your service and your data are decoupled.
2

Since you want the DI to inject CommunicationApi into AdoExtract, you need to make sure that DI container has all information that it needs to create an instance of CommunicationApi, i.e. an ILogger<AdoExtract>, a Func<string, myAuthentication>, and an IConfiguration; otherwise there is no way to call CommunicationApi's constructor. In your case, the most likely thing that is missing is the Func. Although you could definitely inject it by registering an instance for the specific type, I doubt that it is a good idea, because Func<> is not specific enough. Consider creating an interface wrapping it, and registering an instance instead:

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

Register an implementation of this interface in ConfigureServices, then inject it instead of Func, and call AuthenticationForKey("ApiGatewayScope") in the constructor.

Note: passing a full IConfiguration object gives the receiving class access to more information than it needs. Use the Options pattern to address this shortcoming.

3 Comments

Based on John Doe's answer I created the interface ICommunicationApi and added this in ConfigureService services.AddScoped<ICommunicationApi, CommunicationApi>(); Now I am getting the method SendMail. But not the properties like Attachments or IsBodyHtml
@SandeepThomas That's because the interface exposes only the method, not the properties. John's answer shows you an abstraction that is definitely better than what you had, but it probably makes no difference in getting you a fully configured CommunicationApi object: there's no way around providing the parameters for the CommunicationApi's constructor.
@SergeyKalinichenko Not passing IConfiguration is more than just more data than one needs, its also because its not strongly typed to get configurations. That is the user (programmer) should not have to know what is inside that class, can you imagine if all apis said pass me the Iconfiguration object and hopefully you know what I need.
1
  1. Create interface for your CommunicationApi class, where you will expose methods you would like to perform:
public interface ICommunication
{
    Task<int> SendMail();
}
  1. Implement this interface in the concrete class (CommunicationApi)
public class CommunicationApi : ICommunication
  1. Configure dependency in ConfigureServices method:
services.AddScoped<ICommunication, CommunicationApi>();
  1. Rewrite your consumer 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();
    }
}

4 Comments

THanks a lot. Now I am able to get the sendMail method in AdoExtract Class. But the properties Attachments, IsBodyHTML those are not available. That also needs to be in infrerface?
@SandeepThomas, yes, everything you need to work with should be exposed in the interface.
Awesome.. Thanks a lot.. Its all working fine. Btw one last question, my approach is correct, isnt it? or any wise way than I am reach those functions and classes.
Well, you should check out @ORaf answer, his approach is better in terms of software architecture. You should always strive to make interfaces as lightweight as possible.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.