在HostBuilder中调用BuildServiceProvider以获得对服务的访问权

时间:2019-11-15 20:12:30

标签: c# asp.net-core .net-core dotnet-httpclient service-provider

我正在使用.Net Core v2.2。我需要将IHttpClientFactory传递到我的自定义LoggerProvider中。为了从ConfigureLogging中访问此服务,我可以这样做:

.ConfigureLogging((hostingContext, logBuilder) =>
{
    var factory = logBuilder.Services.BuildServiceProvider().GetService(typeof(IHttpClientFactory)) as IHttpClientFactory;
    logBuilder.AddProvider(new SlackLoggerProvider(factory));
})

我认为BuildServiceProvider()最终会创建一组重复的服务。这个可以吗?它正在工作,但是我想知道这是否会影响IHttpClientFactory的生命周期或性能。有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

基于提供的代码的假设是

public class SlackLoggerProvider : ILoggerProvider {
    private readonly IHttpClientFactory clientFactory;

    public SlackLoggerProvider(IHttpClientFactory clientFactory) {
        this.clientFactory = clientFactory;
    }

    //...
}

将必要的类型添加到服务集合中,以便框架可以在运行时对其进行解析

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostContext, services) => {
            services.AddHttpClient();
            services.AddSingleton<ILoggerProvider, SlackLoggerProvider>();
        });

添加的类型将在启动时提供给日志构建器。

在所示示例中,所有AddProvider扩展名都将ILoggerProvider派生实例作为单例添加到服务集合中。

public static ILoggingBuilder AddProvider(this ILoggingBuilder builder, ILoggerProvider provider)
{
    builder.Services.AddSingleton(provider);
    return builder;
}

Source

您可以更进一步并添加扩展名

public static class SlackLoggerBuilderExtension {
    public static ILoggingBuilder AddSlack(this ILoggingBuilder builder) {
        builder.Services.AddHttpClient();
        builder.Services.AddSingleton<ILoggerProvider, SlackLoggerProvider>();
        //or
        //builder.Services.AddSingleton<ILoggerProvider>(sp => 
        //    new SlackLoggerProvider(sp.GetRequiredService<IHttpClientFactory>())
        //);
        return builder;
    }
}

确保添加了必需的依赖项。

二手

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureLogging((hostContext, logBuilder) => {
            logBuilder.AddSlack();
        });

答案 1 :(得分:0)

尝试一下:

.ConfigureLogging(builder =>
{
    builder.Services.AddSingleton<ILoggerProvider, SlackLoggerProvider>();
})

然后您可以照常使用依赖项注入:

public class SlackLoggerProvider
{
    private readonly IHttpClientFactory _clientFactory;

    public SlackLoggerProvider(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }
}

您只需要将IHttpClientFactory添加到服务集合中即可

public void ConfigureServices(IServiceCollection services)
{
    ⋮
    services.AddHttpClient();
    ⋮
}

更新: 我上面提供的答案确实导致了StackOverflowException。我相信这是由于以下原因:

https://github.com/aspnet/HttpClientFactory/blob/7c4f9479b4753a37c8b0669a883002e5e448cc94/src/Microsoft.Extensions.Http/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs#L29

正在构建HttpClient的代码正在调用添加日志记录的代码,在这种情况下,它将再次调用正在构建HttpClient的代码...直到堆栈溢出。

因此,看来您在问题中使用的方法可能是完成您尝试做的事情的最佳方法,因为它可以解决所有问题,然后再将其发送到记录器。