0

I have an api client that in its constructor accepts access token

public class ApiClient : IApiClient
{
    public ApiClient(string accessToken)
}

To get that api token I need to create instance of another class and call method GetTokenAsync()

public class TokenClient
{
     public Task<string> GetTokenAsync();
}

now I want to inject IApiClient to my TestService

public class TestService
{
   public TestService(IApiClient client)
}

However it is not possible register instance in this way

services.AddScoped<IApiClient,ApiClient>(async x=> 
{
  tokenClient = x.GetService<TokenClient>();
  var token = await tokenClient.GetTokenAsync();
  return new ApiClient(token);
}

to overcome that I have created ApiClientProvider class

public class ApiClientProvider()
{
  public async Task<IApiClient> GetClientAsync()
  {
    tokenClient = x.GetService<TokenClient>();
      var token = await tokenClient.GetTokenAsync();
      return new ApiClient(token);
  }
}

and now I inject it to TestService but in every method I have to use

IApiClient apiClient= await _apiClientProvider.GetClientAsync();

I don not like this code, I prefer when dependencies are injected and not resolved in every function, however I do not see any way around. Can you advise if this can be moved to registration or maybe it shouldn't go there.

user1075940
  • 1,086
  • 2
  • 22
  • 46

1 Answers1

2

You should change your design slightly.

Rather than inject a string into your ApiClient, inject an ITokenClient:

public interface ITokenClient
{
    Task<string> GetTokenAsync();
}

public class TokenClient : ITokenClient
{
     public Task<string> GetTokenAsync() { }
}

public class ApiClient : IApiClient
{
    readonly Task<string> tokenTask;

    public ApiClient(ITokenClient tokenClient)
    {
        // Initiate the token request on construction
        tokenTask = tokenClient.GetTokenAsync();
    }

    public async Task SomeMethod()
    {
        string token = await tokenTask;
        // Use your token..
    }
}

Any methods that rely on the token must be async, but as your calling an API they're likely to be async anyway.

Using this method, you simply need to register your clients with the container and no factories / provider types are required.

Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35