Mediatr 范围问题

Posted

技术标签:

【中文标题】Mediatr 范围问题【英文标题】:Mediatr Scope problems 【发布时间】:2019-07-12 14:08:09 【问题描述】:

我正在使用 Mediatr 处理来自队列的消息。我可以得到一个简单的例子来工作。但是,当我尝试将对象注入处理程序时遇到了问题

public class MessageCommandHandler : IRequestHandler<MessageCommand, bool>

    private IMyDependency myDependency;
    public MessageCommandHandler(IMyDependency myDependency)
    
        this.myDependency = myDependency;
    
    
    public Task<bool> Handle(MessageCommand request, CancellationToken cancellationToken)
    
        return Task.FromResult(true);
    

这仅在我将 IMyDependency 注册为瞬态作用域时有效,但是当我将其注册为作用域生命周期时,它会失败并出现错误

Cannot resolve 'MediatR.IRequestHandler`2[MyNamespace.MessageCommand,System.Boolean]' from root provider because it requires scoped service 'MyNamespace.IMyDependency'

我需要能够注入具有作用域生命周期的依赖项。有没有人解决这个问题。

我正在使用 .NET Core 依赖注入框架。设置如下

services.AddHostedService<QueueConsumer>();
services.AddScoped<IMyDependency, MyDependency>();
services.AddMediatR(new Assembly[]  Assembly.GetExecutingAssembly() );

有什么想法吗?

【问题讨论】:

【参考方案1】:

任何时候使用具有作用域生命周期的依赖项,都需要在预先创建的作用域内使用它。在 MVC 的情况下,这将在幕后自动发生,但如果您直接从自己的代码中使用,例如通过控制台应用程序或其他方式,您将需要自己创建范围。

这可以通过注入IServiceScopeFactory 的实例然后使用该工厂创建一个范围然后从该范围检索依赖关系来完成,例如

public class MessageCommandHandler : IRequestHandler<MessageCommand, bool>
    
        private IServiceScopeFactory _serviceScopeFactory;

        public MessageCommandHandler(IServiceScopeFactory serviceScopeFactory) 

        
            _serviceScopeFactory = serviceScopeFactory;
        

        public Task<bool> Handle(MessageCommand request, CancellationToken cancellationToken)
        
            using (var scope = _serviceScopeFactory.CreateScope())
            
                var scopedServices = scope.ServiceProvider;
                var myDependency = scopedServices.GetRequiredService<IMyDependency>();
                return Task.FromResult(true);
            
        
    

但是(请注意,上面的代码未经测试),在我自己的系统中,我几乎总是会围绕发送中介请求的任何内容创建范围,在这种情况下,任何 Scoped 依赖项仍将在此范围内自动注入,例如

... // some other calling class / Main method etc..

using (var scope = _serviceScopeFactory.CreateScope())
    var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
    mediator.Send(new MessageCommand());

【讨论】:

_serviceScopeFactory 应该是 readonly。不过答案很好。

以上是关于Mediatr 范围问题的主要内容,如果未能解决你的问题,请参考以下文章

MediatR 发布和 MediatR 发送

Mediatr - 使缓存无效/更新的正确位置在哪里

使用 ServiceStack 设置 MediatR

使用 MediatR 链接处理程序

无法解析“MediatR.IMediator”类型的服务

使用 Moq 模拟 MediatR 3