MassTransit如何禁用publish filter的新DI范围以共享Accessor实例值
解决方案
方案1:使用AsyncLocal实现IAccessor(最推荐)
该方案无需修改MassTransit默认配置,适配性最高,核心是利用AsyncLocal<T>在同一异步调用链的不同DI Scope之间共享数据:
public class Accessor : IAccessor { private static readonly AsyncLocal<Guid> _idStorage = new AsyncLocal<Guid>(); public Guid Id { get => _idStorage.Value; set => _idStorage.Value = value; } }
IAccessor依然保持Scoped生命周期注册即可,业务代码中设置的Id会被同异步链路下的过滤器正常读取。
方案2:发布时传入当前Scope的ServiceProvider
如果不需要修改Accessor实现,可以在调用Publish方法时传入当前请求的IServiceProvider,MassTransit会直接使用传入的服务提供者解析依赖,不会新建Scope:
public class MyProgram { private readonly IAccessor _accessor; private readonly IBus _messageBus; private readonly IServiceProvider _serviceProvider; public MyProgram(IAccessor accessor, IBus messageBus, IServiceProvider serviceProvider) { _accessor = accessor; _messageBus = messageBus; _serviceProvider = serviceProvider; } public async Task DoThing() { _accessor.Id = Guid.NewGuid(); // 传入当前服务提供者复用现有Scope await _messageBus.Publish(new Message(), CancellationToken.None, _serviceProvider); } }
方案3:全局关闭发布管道自动创建Scope
如果需要全局生效,可在MassTransit配置中直接关闭发布时新建Scope的逻辑:
builder.Services.AddMassTransit(x => { // 其他总线注册逻辑 x.UsingInMemory((context, cfg) => { // 全局关闭发布管道自动建Scope逻辑 cfg.ConfigurePublish(p => p.UseExecute(c => c.CreateNewScope = false)); cfg.UsePublishFilter(typeof(MyPublishFilter<>), context); cfg.ConfigureEndpoints(context); }); });
注意:全局关闭后会影响所有发布过滤器的依赖解析,若过滤器中存在非上下文共享的Scoped依赖,可能出现异常,需谨慎使用。
内容的提问来源于stack exchange,提问作者Neil
相关产品推荐
相关产品推荐

