'How to instanciate ServiceCollection and use IHttpCientFactory in a .NET Core ConsoleApp?

i have the following code, and when Running this code i can validate that the Client is created in the ConfigureService Method, when ConfigureServices are called.

  1. Main Question: How can i get the access to clientFactory in the MainAsync Task?
  2. Secondary Priority: How do i instanciate the serviceColletion through a constructor

namespace CustomeNameSpace
{
  public class Program
  {
    public static IConfigurationRoot configuration;
    private static readonly IServiceCollection serviceCollection;

    public static void Main(string[] args)
    {
      ConfigureServices();
      ILogger logger = NullLogger.Instance;
      MainAsync(logger).GetAwaiter().GetResult();
    }

    private static async Task MainAsync(ILogger log) 
    {
      // Need to use httpClientAt this location....
      // var clientFactory = .....
      // var client = clientFactory.CreateClient()
    }

    public static void ConfigureServices()
    {
      var serviceCollection = new ServiceCollection();
      serviceCollection.AddHttpClient();

      var clientFactory = serviceCollection.BuildServiceProvider().GetRequiredService<IHttpClientFactory>();
      //var client = clientFactory.CreateClient();

      configuration = new ConfigurationBuilder().SetBasePath(Directory.GetParent(AppContext.BaseDirectory).FullName)
        .AddJsonFile("local.settings.json", false)
        .Build();
    }
  }
}


Solution 1:[1]

This code needs to be refactored to follow a more stream lined approach to applying dependency injection.

public class Program {

    //async Task Main feature allowed from C# 7.1+
    public static async Task Main(string[] args) {
        //Composition root
        IServiceProvider services = ConfigureServices();
        
        ILogger logger = NullLogger.Instance;
        
        IHttpClientFactory clientFactory = service.GetRequiredService<IHttpClientFactory>();
        HttpClient client = clientFactory.CreateClient();
        
        IConfiguration configuration = service.GetRequiredService<IConfiguration>();
        
        await RunAsync(logger, client, configuration);
    }

    private static async Task RunAsync(ILogger log, HttpClient client, IConfiguration configuration) {
      
      //...
      
    }

    public static IServiceProvider ConfigureServices() {
        IServiceCollection services = new ServiceCollection();
        services.AddHttpClient();

        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetParent(AppContext.BaseDirectory).FullName)
            .AddJsonFile("local.settings.json", false)
            .Build();
        services.AddSingleton<IConfigurationRoot>(configuration);
        services.AddSingleton<IConfiguration>(configuration);
        
        return services.BuildServiceProvider();
    }
}

Note how any required services can now be resolved and used as needed from the service provider.

This could be further improved by encapsulating the primary functionality in a class and resolving it from the service provider so that all explicit dependencies can be resolved and injected directly by the service container.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1