【问题标题】:Calling BuildServiceProvider inside of HostBuilder to get access to a service在 HostBuilder 中调用 BuildServiceProvider 以访问服务
【发布时间】:2020-03-12 00:30:12
【问题描述】:

我正在使用 .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 的生命周期或性能。有没有更好的方法来做到这一点?

【问题讨论】:

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


    【解决方案1】:

    试试这个:

    .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 的代码...直到堆栈溢出。

    因此,您在问题中使用的方法似乎是执行您尝试做的事情的最佳方法,因为它在将所有问题发送到您的记录器之前解决了所有问题。

    【讨论】:

    • 这会引发 StackOverFlowException。如果我将 IHttpClientFactory 作为对 SlackLoggerProvider 的依赖项删除,它不会引发异常。
    • 我试过了,但它仍然给出了 StackOverflowException:stackoverflow.com/questions/50991469/…
    【解决方案2】:

    基于提供的代码的假设是

    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();
            });
    

    【讨论】:

      猜你喜欢
      • 2021-11-05
      • 2021-11-04
      • 1970-01-01
      • 2013-12-19
      • 1970-01-01
      • 1970-01-01
      • 2015-02-04
      • 2021-11-10
      • 1970-01-01
      相关资源
      最近更新 更多