Asp.Net Core 无法访问已释放的上下文实例

Posted

技术标签:

【中文标题】Asp.Net Core 无法访问已释放的上下文实例【英文标题】:Asp.Net Core Cannot access a disposed context instance 【发布时间】:2021-06-29 06:55:57 【问题描述】:

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

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

我得到的错误是:

无法访问已释放的上下文实例。造成这种情况的一个常见原因 错误正在处理已解决的上下文实例 依赖注入,然后尝试使用相同的上下文 在您的应用程序的其他地方实例。如果您是 在上下文实例上调用“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" );
    

服务

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");
    

可能是什么问题?

【问题讨论】:

能否分享一下starup.cs文件 【参考方案1】:

我很确定 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&lt;IActionResult&gt;以支持async调用。

如果您确实想稍后在回调中调用_service.GetAllAsync()(而不是在请求Get 时),则需要注入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 注入控制器的构造函数(因为它根本没有被使用)。 ​

【讨论】:

以上是关于Asp.Net Core 无法访问已释放的上下文实例的主要内容,如果未能解决你的问题,请参考以下文章

注入 DbContext 时无法访问 ASP.NET Core 中已释放的对象

在 Asp.NET core 中触发 Quartz 作业时释放上下文

C#:使用 IQueryable 注入 DbContext 时,无法访问 ASP.NET Core 中的已处置对象

在 ASP.NET Core Authorize-Attribute 中使用带有 DbContext 的存储库:“无法访问已处置的对象”

无法访问已释放的上下文实例 EF 核心

ASP.NET Core Cors 已启用但无法正常工作