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

Ger*_*hes 5 signalr entity-framework-core asp.net-core asp.net-core-signalr

我正在尝试实现 SignalR 以便使用来自角度前端应用程序的数据。

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

我收到的错误是:

无法访问已释放的上下文实例。导致此错误的一个常见原因是处置从依赖项注入解析的上下文实例,然后尝试在应用程序的其他位置使用相同的上下文实例。如果您在上下文实例上调用“Dispose”或将其包装在 using 语句中,则可能会发生这种情况。如果您使用依赖项注入,则应该让依赖项注入容器负责处理上下文实例。对象名称:“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" });
    }
}
Run Code Online (Sandbox Code Playgroud)

服务

public Task<List<LiveMonitoring>> GetAllAsync()
{
    return _repository.GetAll().Take(100).ToListAsync();
}
Run Code Online (Sandbox Code Playgroud)

存储库

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

可能是什么问题呢?

Kin*_*ing 4

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

\n

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

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

我们需要将返回类型更改GetTask<IActionResult>支持async调用。

\n

如果您实际上想_service.GetAllAsync()稍后Get在回调内调用(而不是在请求时),则需要注入 anIServiceScopeFactory来为该回调内的服务创建一个作用域,如下所示:

\n
public IActionResult Get([FromServices] IServiceScopeFactory serviceScopeFactory)\n{\n    var timerManager = new TimerManager(async () => \n                           {\n                             using(var scope = serviceScopeFactory.CreateScope()){\n                               var service = scope.ServiceProvider.GetRequiredService<ILiveMonitoringService>();                                   \xe2\x80\x8b\n                               \xe2\x80\x8bvar liveMonitorings = await service.GetAllAsync();\n                               \xe2\x80\x8breturn await _hub.Clients.All.SendAsync("transferchartdata", liveMonitorings);\n                            \xe2\x80\x8b }\n                           \xe2\x80\x8b});\n   \xe2\x80\x8breturn Ok(new { Message = "Request Completed" });\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n