【问题标题】:Cannot access a disposed object (IServiceProvider) while using MediatR in tests在测试中使用 MediatR 时无法访问已处置的对象 (IServiceProvider)
【发布时间】:2021-09-02 02:43:43
【问题描述】:

我收到以下错误:

Cannot access a disposed object.
Object name: 'IServiceProvider'.

尝试调用_mediator.Send 方法时。

只有在我尝试测试控制器的方法时才会发生这种情况。每当从 api 调用控制器时,它似乎都可以正常工作。

控制器:

public class Controller : ControllerBase
{
    private readonly IMediator mediator;
    public Controller(IMediator mediator)
    {
        this.mediator = mediator;
    }

    [HttpPost]
    public async Task<IActionResult> Post(Command command)
    {
        try
        {
            await mediator.Send(command); // exception occurs here
            return Ok();

        }
        catch (Exception ex)
        {
            return BadRequest(ex.InnerException?.Message ?? ex.Message);
        }
    }
}

请求处理程序:

  public class CommandHandler
    : IRequestHandler<Command, bool>
    {
        private readonly AppDbContext dbContext;
        public CommandHandler(AppDbContext dbContext)
        {
            this.dbContext = dbContext;
        }
        public async Task<bool> Handle(Command request, CancellationToken cancellationToken)
        {
            try
            {
                await dbContext.Companies.AddAsync(new Company(request.CompanyId, request.CompanyName), cancellationToken);
                await dbContext.SaveChangesAsync(cancellationToken);
                return true;
            }
            catch(Exception)
            {
                throw;
            }
        }
    }

MediatR 是这样注册的:

services.AddMediatR(Assembly.GetExecutingAssembly());

我正在尝试使用真实的数据库连接来测试这个控制器。

protected Controller GetController() // method where controller is created and mediatR injected
{
    using var scope = _scopeFactory.CreateScope();
    var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
    return new Controller(mediator);
}



protected async Task<IActionResult> PostControllerMethod(Command command) // this method is call in test method
    => await GetController().Post(command);

解决问题的唯一方法是将MediatR注册为单例:

   services.AddMediatR(mediatRServiceConfiguration => mediatRServiceConfiguration.AsSingleton(), Assembly.GetExecutingAssembly());

我不确定后果。

【问题讨论】:

  • 我不是 100% 确定如何更好地做到这一点,但发生这种情况的原因是您在 GetController() 中处理范围。这将处理从它获取的所有作用域和瞬态依赖项。您可能需要在开始测试时创建范围并获取服务,并在测试结束时处置范围。

标签: asp.net-core dependency-injection mediatr


【解决方案1】:

在“使用”结束时,作用域被释放。 当您将此“调解器”返回给控制器时,范围已被释放并且“调解器”无法访问。 尝试在您要使用的地方解析“调解员”

protected Controller GetController() // method where controller is created and mediatR injected
{
    using var scope = _scopeFactory.CreateScope();
    var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
    return new Controller(mediator);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-19
    相关资源
    最近更新 更多