Home > Back-end >  How to pass IOption into IServiceCollection (Best Practice) in dotnet6
How to pass IOption into IServiceCollection (Best Practice) in dotnet6

Time:07-27

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

CodePudding user response:

I would honestly just pass IConfiguration to AddConnectServices and read it manually.

Another option, you could create a wrapper around the HttpClient e.g. IMyHttpClient, and then in its implementation's constructor you would take in IOptions<SiteConfiguration> and the IHttpClientFactory (how to setup) and use the factory to get the HttpClient in your MyHttpClient implementation (so it's lifetime is managed properly, please read here about that, especially if you go with newing it yourself).

You could implement SendAsync which just passes the request along and returns it. Could also be a nice place to have some logging for all your request/responses, or that could even be on a decorator for your IMyHttpClient.

CodePudding user response:

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>()
  • Related