1

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

  1. Main Question: How can I get access to clientFactory in the MainAsync Task?
  2. Secondary Priority: How do I instantiate 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 httpClient At 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();
        }
    }
}
Palle Due
  • 5,929
  • 4
  • 17
  • 32
otk
  • 357
  • 5
  • 23

1 Answers1

3

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.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Hi, so i test this in my app, but i dont get it to run. I have a CONSOLE-application. You sure you can have a async Main in a Console-App? Did you actually test it, i ask this since you use service.Add and not services, which is defined by "IServiceCollection services". I use .net 5.0 which should equal to C# 9 by default, but still dont work for me. – otk Apr 05 '22 at 11:48
  • 1
    @otk that was a typo. Also check here about async main https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.1/async-main#detailed-design – Nkosi Apr 05 '22 at 11:50
  • Hi, thanks i got it working. Before i accept answer, i got a question: 1. in order to use the RunAsync Method i need to instantiate the Program class: Program prg = new Program(). And use await prg.RunAsync. Is it bad practice to do this inside it's own class, or what do i not understand here? – otk Apr 05 '22 at 12:21
  • @otk Another Typo my friend. You don't need to instantiate Program if RunAsync is static in this case. – Nkosi Apr 05 '22 at 12:23