如何将IBus传入MassTransit消费者构造函数及IMapper使用相关问题
关于消费者发布消息的依赖获取问题
你当前的注册方式有两处可优化的问题:
- 不要手动调用
services.BuildServiceProvider()创建容器,该操作会生成独立的根容器副本,和AspNetCore默认的服务容器不共享实例,容易引发服务生命周期混乱、单例重复创建等问题。 - 不需要自己在构造函数中从服务容器获取
IBus,更不需要手动写工厂实例化消费者,有两种更合理的实现方案:- 最推荐的方案:
ConsumeContext本身已经实现了发布消息的接口,直接在Consume方法中调用context.Publish即可,不需要注入任何发布相关的依赖,该方式会自动继承当前消费消息的链路上下文(如关联ID、自定义头等),链路追踪的兼容性更好。 - 如果你确实需要单独注入发布能力,可以直接在消费者构造函数中声明
IPublishEndpoint(更符合接口隔离原则,仅包含发布相关方法)或者IBus作为参数,MassTransit的官方DI集成会自动完成注入,不需要你手动传递参数。
- 最推荐的方案:
关于AutoMapper的初始化问题
你当前在消费者构造函数中创建MapperConfiguration的写法不符合规范:
MapperConfiguration是重量级初始化对象,AutoMapper官方要求全局仅初始化一次,设置为单例即可,每次消费都新建配置会带来严重的不必要性能开销。- 正确的做法是在服务注册阶段完成AutoMapper的初始化,将
IMapper注入到容器中,再通过消费者构造函数直接注入即可。
正确的实现示例
服务注册代码
// 全局初始化AutoMapper,自动注册IMapper到容器 services.AddAutoMapper(typeof(MappingProfile)); services.AddMassTransit(x => { // 注册消费者到DI容器 x.AddConsumer<ConsumerProcessingStatusChange>(); x.UsingRabbitMq((context, cfg) => { cfg.ReceiveEndpoint(RabbitMqOptions.StatusChangeQueueName, e => { // 用DI容器自动配置消费者,自动注入所有依赖 e.ConfigureConsumer<ConsumerProcessingStatusChange>(context); }); }); });
消费者代码
public class ConsumerProcessingStatusChange : IConsumer<***> { private readonly IMapper _mapper; // 直接注入需要的依赖,无需传递IServiceProvider public ConsumerProcessingStatusChange(IMapper mapper) { _mapper = mapper; } public async Task Consume(ConsumeContext<***> context) { // 直接用消费上下文的Publish方法发布消息 await context.Publish(_mapper.Map<***>(context.Message)); } }
内容的提问来源于stack exchange,提问作者Christy Pirumova
相关产品推荐
相关产品推荐

