NServiceBus 7.5迁移至8:WindsorContainer依赖适配问题求助
NServiceBus 8 迁移Windsor容器依赖加载问题
问题背景
我们之前基于NServiceBus 7.5 + Windsor容器开发,通过FromAssemblyContaining批量加载项目依赖,用以下代码关联NServiceBus和现有容器:
endpointConfiguration.UseContainer<WindsorBuilder>(c => c.ExistingContainer(container));
服务运行正常,但升级到NServiceBus 8后,UseContainer方法被移除,官方要求通过AddSingleton、AddScoped或AddTransient逐个注册依赖。但我们没法枚举FromAssemblyContaining加载的所有服务,不知道如何批量迁移现有容器中的依赖。
尝试过的方案及错误
我们参考官方迁移文档实现了以下代码:
var endpointConfiguration = new EndpointConfiguration("EndpointName"); _endpointCustomization.Customize(endpointConfiguration); // 配置端点相关内容 var serviceCollection = new ServiceCollection(); var container = _endpointCustomization.Container(); // 获取已加载好的Windsor容器 var serviceProvider = WindsorRegistrationHelper.CreateServiceProvider(container, serviceCollection); var startableEndpoint = EndpointWithExternallyManagedContainer.Create(endpointConfiguration, serviceCollection); var _endpointInstance = await startableEndpoint.Start(serviceProvider); await _endpointCustomization.Start(_endpointInstance);
但调用第一个await时抛出异常:
Castle.MicroKernel.ComponentNotFoundException: 未找到支持服务NServiceBus.Unicast.Messages.MessageMetadataRegistry的组件
解决方案
问题根源是NServiceBus 8所需的内部服务没有被注册到Windsor容器中。正确的做法是先让NServiceBus把自身依赖注册到ServiceCollection,再将Windsor容器中的现有服务批量导入到ServiceCollection,最后用整合后的服务集合创建ServiceProvider并启动端点。
正确代码示例
var endpointConfiguration = new EndpointConfiguration("EndpointName"); _endpointCustomization.Customize(endpointConfiguration); // 1. 让NServiceBus将自身所需的内部服务注册到ServiceCollection var serviceCollection = new ServiceCollection(); endpointConfiguration.ApplyCommonConfiguration(serviceCollection); // 2. 获取已完成依赖加载的Windsor容器 var container = _endpointCustomization.Container(); // 3. 批量将Windsor容器中的服务导入到ServiceCollection foreach (var component in container.Kernel.GetAssignableHandlers(typeof(object))) { var serviceType = component.ComponentModel.Service; var implementationType = component.ComponentModel.Implementation; var lifestyle = component.ComponentModel.LifestyleType; // 根据Windsor生命周期映射到ServiceCollection的注册方式 switch (lifestyle) { case LifestyleType.Singleton: serviceCollection.AddSingleton(serviceType, implementationType); break; case LifestyleType.Scoped: serviceCollection.AddScoped(serviceType, implementationType); break; case LifestyleType.Transient: serviceCollection.AddTransient(serviceType, implementationType); break; // 处理自定义生命周期,比如PerWebRequest等,可根据实际需求调整 default: serviceCollection.AddTransient(serviceType, implementationType); break; } } // 4. 创建ServiceProvider并启动端点 var serviceProvider = serviceCollection.BuildServiceProvider(); var startableEndpoint = EndpointWithExternallyManagedContainer.Create(endpointConfiguration, serviceCollection); var _endpointInstance = await startableEndpoint.Start(serviceProvider); await _endpointCustomization.Start(_endpointInstance);
关键说明
ApplyCommonConfiguration是NServiceBus 8新增的方法,用于将端点运行所需的内部服务(比如MessageMetadataRegistry)注册到ServiceCollection,这是之前方案缺失的核心步骤- 通过遍历Windsor容器的
GetAssignableHandlers,可以批量获取所有已注册的服务,无需逐个枚举,完美替代FromAssemblyContaining的批量加载逻辑 - 注意保持Windsor和
ServiceCollection的生命周期一致,避免因生命周期不匹配导致的问题
内容的提问来源于stack exchange,提问作者Projector
相关产品推荐
相关产品推荐

