Azure Functions v4进程内Startup类中Autofac无法解析ILogger<T>
在Azure Functions v4进程内版本的Startup类中使用Autofac集成时,解析依赖获取ILoggerConfigureEventBus方法中解析IEventBus时,触发AddEventBus里的services.AddSingleton<IEventBus, EventBusServiceBus>逻辑,但无法解析ILogger<EventBusServiceBus>。尝试多种方式均无效:从ServiceProvider获取失败;实例化LoggerFactory得到空日志记录器;从容器解析LoggerFactory再创建Logger也未成功。
相关代码
简化后的Startup类代码
internal class Startup : FunctionsStartup { public override void Configure(IFunctionsHostBuilder builder) { builder.Services.AddSingleton(GetContainer(builder.Services)); builder.Services.AddScoped<LifetimeScopeWrapper>(); builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IJobActivator), typeof(AutofacJobActivator))); builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IJobActivatorEx), typeof(AutofacJobActivator))); builder.Services.AddCustomIntegrations(configuration); builder.Services.AddEventBus(configuration); var serviceProvider = builder.Services.BuildServiceProvider(); ConfigureEventBus(serviceProvider); } private static IContainer GetContainer(IServiceCollection serviceCollection) { var containerBuilder = new ContainerBuilder(); containerBuilder.Populate(serviceCollection); containerBuilder.RegisterModule<LoggerModule>(); containerBuilder.RegisterAssemblyTypes(typeof(Startup).Assembly) .InNamespaceOf<Function1>(); return containerBuilder.Build(); } private void ConfigureEventBus(ServiceProvider sp) { var eventBus = sp.GetRequiredService<BuildingBlocks.EventBus.Abstractions.IEventBus>(); } }
扩展方法代码
static class CustomExtensionsMethods { public static IServiceCollection AddCustomIntegrations(this IServiceCollection services, IConfiguration configuration) { services.AddSingleton<IServiceBusPersisterConnection>(sp => { var serviceBusConnectionString = configuration["EventBusConnection"]; var subscriptionClientName = configuration["SubscriptionClientName"]; return new DefaultServiceBusPersisterConnection(serviceBusConnectionString); }); return services; } public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) { services.AddSingleton<IEventBus, EventBusServiceBus>(sp => { var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); var autoFacContainer = sp.GetRequiredService<IContainer>(); var iLifetimeScope = autoFacContainer.Resolve<ILifetimeScope>(); // 以下尝试均失败 // var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); // var loggerFactory = new LoggerFactory(); // var logger = loggerFactory.CreateLogger<EventBusServiceBus>(); // var loggerFactory = autoFacContainer.Resolve<ILoggerFactory>(); // var logger = loggerFactory.CreateLogger<EventBusServiceBus>(); // autoFacContainer.Resolve<ILogger<EventBusServiceBus>>(); var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); string subscriptionName = configuration["SubscriptionClientName"]; return new EventBusServiceBus(serviceBusPersisterConnection, logger, eventBusSubcriptionsManager, iLifetimeScope, subscriptionName); }); services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); return services; } }
解决方案
1. 核心问题:提前构建ServiceProvider
Startup中builder.Services.BuildServiceProvider()会创建未完全初始化的服务提供者,此时Azure Functions的日志系统还未完成配置,导致无法获取有效的ILogger
2. 调整容器构建顺序
确保所有服务添加完成后再构建Autofac容器,避免容器提前构建导致后续服务未被注入。
3. 正确从Autofac作用域解析ILogger
Azure Functions会自动将日志服务注册到容器中,只需从Autofac的ILifetimeScope中直接解析ILogger<EventBusServiceBus>即可。
修改后的代码示例
修改后的Startup类
internal class Startup : FunctionsStartup { public override void Configure(IFunctionsHostBuilder builder) { // 先添加所有业务服务 builder.Services.AddCustomIntegrations(configuration); builder.Services.AddEventBus(configuration); // 再构建Autofac容器 var containerBuilder = new ContainerBuilder(); containerBuilder.Populate(builder.Services); containerBuilder.RegisterModule<LoggerModule>(); containerBuilder.RegisterAssemblyTypes(typeof(Startup).Assembly) .InNamespaceOf<Function1>(); var container = containerBuilder.Build(); builder.Services.AddSingleton(container); // 配置Autofac激活器 builder.Services.AddScoped<LifetimeScopeWrapper>(); builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IJobActivator), typeof(AutofacJobActivator))); builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IJobActivatorEx), typeof(AutofacJobActivator))); // 移除提前构建ServiceProvider的代码,改为在函数启动时初始化EventBus } }
修改后的AddEventBus扩展方法
public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) { services.AddSingleton<IEventBus, EventBusServiceBus>(sp => { var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); var lifetimeScope = sp.GetRequiredService<ILifetimeScope>(); // 直接从Autofac作用域解析有效的ILogger<T> var logger = lifetimeScope.Resolve<ILogger<EventBusServiceBus>>(); var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); string subscriptionName = configuration["SubscriptionClientName"]; return new EventBusServiceBus(serviceBusPersisterConnection, logger, eventBusSubcriptionsManager, lifetimeScope, subscriptionName); }); services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); return services; }
4. 延迟初始化EventBus
如果需要在启动时配置EventBus,可以在第一个函数的构造函数中注入IEventBus并执行配置,或者使用IHostedService处理启动逻辑(Azure Functions支持Hosted Service)。
内容的提问来源于stack exchange,提问作者LockTar

