Asp.Net 核心无法访问已处置的上下文实例

Asp.Net Core Cannot access a disposed context instance

我正在尝试实施 SignalR 以使用来自 angular 前端应用程序的数据。

我已经检查了 google 上所有我能找到的结果,但我仍然无法解决我的问题。

我得到的错误是:

Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'AdminContext'

控制器

[Route("api/[controller]")]
[ApiController]
public class ChartController : ControllerBase
{
    private IHubContext<ChartHub> _hub;
    private readonly ILiveMonitoringService _service;

    public ChartController(IHubContext<ChartHub> hub, ILiveMonitoringService service)
    {
        _hub = hub;
        _service = service;

    }
    public IActionResult Get()
    {
        var timerManager = new TimerManager(async () => await _hub.Clients.All.SendAsync("transferchartdata", await _service.GetAllAsync()));
        return Ok(new { Message = "Request Completed" });
    }
}

服务

public Task<List<LiveMonitoring>> GetAllAsync()
{
    return _repository.GetAll().Take(100).ToListAsync();
}

存储库

public IQueryable<TEntity> GetAll()
{
    try
    {
        return _adminContext.Set<TEntity>();
    }
    catch (Exception ex)
    {
        throw new Exception("Couldn't retrieve entities");
    }
}

可能是什么问题?

我很确定 TimerManager 是您的问题。您没有显示它的声明,但看起来它的构造函数接受一个回调,在稍后的某个时间点被调用。这就是问题所在。您的作用域服务 _service 在回调中被捕获,并在稍后的某个时间点 当请求已经结束 时使用。因此,在请求结束后,DbContext 将被释放,您的 _service 将使用已释放的上下文。

解决方法是先简单地获取数据,然后再将其传递到回调中,这样 _service 就不会被捕获到该回调中,如下所示:

public async Task<IActionResult> Get()
{
    var liveMonitorings = await _service.GetAllAsync();
    var timerManager = new TimerManager(async () => await _hub.Clients.All.SendAsync("transferchartdata", liveMonitorings));
    return Ok(new { Message = "Request Completed" });
}

我们需要将 Get 的返回类型更改为 Task<IActionResult> 以支持 async 调用。

如果你真的想在稍后的某个时间(而不是在请求 Get 时)在回调中调用 _service.GetAllAsync(),你需要注入一个 IServiceScopeFactory 来创建一个该回调内的服务范围,如下所示:

public IActionResult Get([FromServices] IServiceScopeFactory serviceScopeFactory)
{
    var timerManager = new TimerManager(async () => 
                           {
                             using(var scope = serviceScopeFactory.CreateScope()){
                               var service = scope.ServiceProvider.GetRequiredService<ILiveMonitoringService>();                                   ​
                               ​var liveMonitorings = await service.GetAllAsync();
                               ​return await _hub.Clients.All.SendAsync("transferchartdata", liveMonitorings);
                            ​ }
                           ​});
   ​return Ok(new { Message = "Request Completed" });
}

这样你就不需要将你的 _service 注入到控制器的构造函数中(因为它根本没有被使用)。