Search code examples
.net.net-coredependency-injectionioptionsmonitor

How to pass IOption into IServiceCollection (Best Practice) in .NET 6


I have a appsettings.json with below:

{
  "$schema": "./appsettings-schema.json",  
  "ConnectionStrings": {
    "dbDSN": "Server=.;Database=demodb;User Id=demo;Password=123",    
  },
  "ConnectPoint": {
    "siteAPI": "https://workersite.com/api"
  }
}

The class as below :

public record SiteConfiguration {
    public ConnectPoint ConnectPoint { get; set; };
}
public record ConnectPoint {
    public string siteAPI { get; set; } = string.Empty;
}

and I create static class ServiceInjection like

public static class ServiceInjection {
    public static IServiceCollection AddConnectServices(this IServiceCollection services, IOptions<SiteConfiguration> configuration) {
        
        services.AddSingleton<IAPIClient>(
            new APIClient(              
                    new HttpClient {
                        BaseAddress = new Uri(configuration.Value.ConnectPoint.siteAPI)
                    }));
        return services;
    }
}

In the startup.cs, under ConfigureServices() It can be work as below code:

services.Configure<SiteConfiguration>();
var serviceProvider = services.BuildServiceProvider();
var opt = serviceProvider.GetRequiredService<IOptions<SiteConfiguration>>().Value;
services.AddConnectServices(opt.value);

But I want to change Ioptionmonitor and don't want to use services.BuildServiceProvider() in dotnet6, can I know how to do it?

Thank you


Solution

  • Have you tried bundling everything in one extension method to provide IOptions/IOptionsMonitor with the inline ServiceProvider (sp)

    public static class ServiceInjection 
    {
        public static IServiceCollection AddConnectServices(this IServiceCollection services) {
            
            services.Configure<SiteConfiguration>();
            services.AddSingleton<IAPIClient>(sp =>
            {
                var options = sp.GetRequiredService<IOptions<SiteConfiguration>>();
                var client = new APIClient(              
                        new HttpClient {
                            BaseAddress = new Uri(options.Value.ConnectPoint.siteAPI)
                        });
    
            }
            return services;
        }
    }
    

    ... or to improve one step forward use it with IHttpClientFactory like this instead of creating the HttpClient by yourself:

    services.AddHttpClient<IAPIClient, APIClient>();
    services.AddSingleton<IAPIClient, APIClient>()