IHostBuilder.ConfigureServices 引导程序中的简单注入器 LoggerFactory

问题描述

我将 Simple Injector 与通用主机 nuget 包一起使用,一切都很好,只是我在注册顺序上遇到了障碍。

我有一个返回两个接口 IMessagePublisherIMessageSubscriber 的构建器类,这个构建器类也需要一个 ILoggerFactory

我无法使用 ILoggerFactory,因为它尚未配置,并且无法调用 container.GetInstance<ILoggerFactory>,因为在调用代码时容器仍在使用注册进行引导。

我的主要主持人在这里

var host = CreateHostBuilder(args)
   .UseSerilog((hostContext,loggerConfiguration) =>
   {
      var setting = hostContext.Configuration
        .GetSection(Settings.Name).GetAndAssert<Settings>();

      if (setting.IsDebug == true)
          loggerConfiguration.MinimumLevel.Debug();
      else
          loggerConfiguration.MinimumLevel.information();

      loggerConfiguration
          .MinimumLevel.Override("Microsoft",LogEventLevel.Warning)
          .Enrich.FromLogContext()
          .Writeto.Console()
          .Writeto.File("logging.log");
  })
  .Build()
  .UseSimpleInjector(container);

我的 CreateHostBuilder 如下(我的问题出在 builder.Create 方法中):

public static IHostBuilder CreateHostBuilder(string[] args)
{
    return Host
        .CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostContext,builder) =>
        {
            if (hostContext.HostingEnvironment.IsDevelopment())
            {
                builder.AddUserSecrets<Program>();
            }
        })
        .ConfigureServices((hostContext,services) =>
        {
            services.AddSimpleInjector(container,options =>
            {
                options.AddHostedService<Worker>();
                options.AddLogging();

                var mqttSettings = hostContext                                   
                    .Configuration
                    .GetSection(MqttSettings.Name)
                    .GetAndAssert<MqttSettings>();

                var builder = new MqttMessageBusBuilder(mqttSettings);

                builder.Create(
                    new[] { new MessagePackSerializer() },new IdentifyUsingTransportHeaders(),/* below is not allowed */
                    container.GetInstance<ILoggerFactory>,// i also dont kNow where to get IloggerFactory if not yet configured
                    out var messagePublisher,out var messageSubscriber,mqttSettings.isDebug);

                container.RegisterInstance(messagePublisher);
                container.RegisterInstance(messageSubscriber);
            });
        });
}

我无法使用单例并将实例化推迟到需要时,因为我需要构建器返回 IMessagePublisherIMessageSubscriber 实例。

否则我会在 container.GetInstance<ILoggerFactory>() 有效的情况下使用以下内容

// register factory to create polygonWebsocket
container.RegisterSingleton( () => {
    var settings = container.GetInstance<Settings>();
    var secrets = container.GetInstance<Secrets>();

    return new polygonWebsocket(
            secrets.polygonIoApiKey,settings.polygonWebSocketUrl,settings.polygonReconnectTimeout,container.GetInstance<ILoggerFactory>()
    });

如何在 MqttMessageBusBuilder.Create 引导期间将 ILoggerFactory 注入我的 CreateHostBuilder 方法

解决方法

这个问题与 Simple Injector 无关,因为 ILoggerFactory 来自 IServiceCollection 及其最后的 IServiceProvider,这是一个先有鸡还是先有蛋的困境。您想在 ILoggerFactory 期间将 MqttMessageBusBuilder.Create 提供给 ConfigureServices,而 ILoggerFactory 只能在可用时从 IServiceProvider 解析,这是在稍后的阶段。

据我所知,您可以做三件事:

  1. ILoggerFactory 中拉入 IServiceCollection,因为此时的注册已经存在于 IServiceCollection 中。
  2. ConfigureServices之后(即在Configure内)推迟注册您的消息接口
  3. 现在进行注册,但使用延迟初始化,以便在解析消息接口时构建。

示例 1:

.ConfigureServices((hostContext,services) =>
{
    var factory = (ILoggerFactory)services
        .Last(s => s.ServiceType == typeof(ILoggerFactory))
        .ImplementationInstance;

    services.AddSimpleInjector(container,options =>
    {
        ...

        var builder = new MqttMessageBusBuilder(mqttSettings);

        builder.Create(
            new[] { new MessagePackSerializer() },new IdentifyUsingTransportHeaders(),factory,out var messagePublisher,out var messageSubscriber,mqttSettings.isDebug);

        container.RegisterInstance(messagePublisher);
        container.RegisterInstance(messageSubscriber);
    });
});

示例 2:

var host = 
    CreateHostBuilder(args)
    .UseSerilog((hostContext,loggerConfiguration) =>
    {
        ...
    })
    .Build()
    .UseSimpleInjector(container);

var factory = host.Services.GetRequiredInstance<ILoggerFactory>();

var mqttSettings = hostContext                                   
    .Configuration
    .GetSection(MqttSettings.Name)
    .GetAndAssert<MqttSettings>();

var builder = new MqttMessageBusBuilder(mqttSettings);

builder.Create(
    new[] { new MessagePackSerializer() },mqttSettings.isDebug);

container.RegisterInstance(messagePublisher);
container.RegisterInstance(messageSubscriber);

return host;

示例 3:

public static IHostBuilder CreateHostBuilder(string[] args)
{
    return Host
        .CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostContext,builder) =>
        {
            if (hostContext.HostingEnvironment.IsDevelopment())
            {
                builder.AddUserSecrets<Program>();
            }
        })
        .ConfigureServices((hostContext,services) =>
        {
            services.AddSimpleInjector(container,options =>
            {
                ...

                var lazy = new Lazy<(
                    IMessagePublisher Publisher,IMessageSubcriber Subscriber)>(() =>
                {
                    var builder = new MqttMessageBusBuilder(mqttSettings);
                
                    builder.Create(
                        new[] { new MessagePackSerializer() },container.GetInstance<ILoggerFactory>(),mqttSettings.isDebug);
                
                    return (messagePublisher,messageSubscriber);
                });

                container.RegisterSingleton(() => lazy.Value.Publisher);
                container.RegisterInstance(() => lazy.Value.Subscriber);
            });
        });
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...