IHostBuilder.ConfigureServices bootstrap 中的简单注入器 LoggerFactory
Simple Injector LoggerFactory in IHostBuilder.ConfigureServices bootstrap
我正在使用带有通用主机 nuget 包的简单注入器,一切都很好,除了我在注册顺序上遇到了障碍。
我有一个构建器 class,它 return 有两个接口,IMessagePublisher
和 IMessageSubscriber
,这个构建器 class 还需要一个 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);
});
});
}
我无法使用 Singleton 并将实例化推迟到需要时,因为我需要构建器 return IMessagePublisher
和 IMessageSubscriber
实例。
否则我会使用下面的 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>()
});
如何在 CreateHostBuilder
bootstrap 期间将 ILoggerFactory 注入我的 MqttMessageBusBuilder.Create
方法?
此问题与 Simple Injector 无关,因为 ILoggerFactory
来自 IServiceCollection
及其最后的 IServiceProvider
,这是一个先有鸡还是先有蛋的困境。您希望在 ConfigureServices
期间将 ILoggerFactory
提供给 MqttMessageBusBuilder.Create
,而 ILoggerFactory
只能在 IServiceProvider
可用时从 IServiceProvider
中解决,这是在稍后阶段。
据我所知,您可以做三件事:
- 从
IServiceCollection
拉入 ILoggerFactory
,因为此时的注册已经存在于 IServiceCollection
。
- 将消息接口的注册推迟到
ConfigureServices
之后(即在 Configure
内)
- 现在进行注册,但使用惰性初始化,以便在解析消息接口时构建。
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() },
new IdentifyUsingTransportHeaders(),
factory,
out var messagePublisher,
out var messageSubscriber,
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() },
new IdentifyUsingTransportHeaders(),
container.GetInstance<ILoggerFactory>(),
out var messagePublisher,
out var messageSubscriber,
mqttSettings.isDebug);
return (messagePublisher, messageSubscriber);
});
container.RegisterSingleton(() => lazy.Value.Publisher);
container.RegisterInstance(() => lazy.Value.Subscriber);
});
});
}
我正在使用带有通用主机 nuget 包的简单注入器,一切都很好,除了我在注册顺序上遇到了障碍。
我有一个构建器 class,它 return 有两个接口,IMessagePublisher
和 IMessageSubscriber
,这个构建器 class 还需要一个 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);
});
});
}
我无法使用 Singleton 并将实例化推迟到需要时,因为我需要构建器 return IMessagePublisher
和 IMessageSubscriber
实例。
否则我会使用下面的 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>()
});
如何在 CreateHostBuilder
bootstrap 期间将 ILoggerFactory 注入我的 MqttMessageBusBuilder.Create
方法?
此问题与 Simple Injector 无关,因为 ILoggerFactory
来自 IServiceCollection
及其最后的 IServiceProvider
,这是一个先有鸡还是先有蛋的困境。您希望在 ConfigureServices
期间将 ILoggerFactory
提供给 MqttMessageBusBuilder.Create
,而 ILoggerFactory
只能在 IServiceProvider
可用时从 IServiceProvider
中解决,这是在稍后阶段。
据我所知,您可以做三件事:
- 从
IServiceCollection
拉入ILoggerFactory
,因为此时的注册已经存在于IServiceCollection
。 - 将消息接口的注册推迟到
ConfigureServices
之后(即在Configure
内) - 现在进行注册,但使用惰性初始化,以便在解析消息接口时构建。
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() },
new IdentifyUsingTransportHeaders(),
factory,
out var messagePublisher,
out var messageSubscriber,
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() },
new IdentifyUsingTransportHeaders(),
container.GetInstance<ILoggerFactory>(),
out var messagePublisher,
out var messageSubscriber,
mqttSettings.isDebug);
return (messagePublisher, messageSubscriber);
});
container.RegisterSingleton(() => lazy.Value.Publisher);
container.RegisterInstance(() => lazy.Value.Subscriber);
});
});
}