You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core使用SocketIOClientDotNet报错:无法访问已释放对象求助

解决SocketIOClientDotNet在ASP.NET Core启动时的ObjectDisposedException问题

这个报错我之前也碰到过,核心原因是Scoped生命周期的服务和应用启动阶段的生命周期不匹配,咱们一步步理清楚:

问题根源

你在ConfigureServices里注册了Scoped的ISocketIoService,而Configure方法是在应用启动时执行的——这个阶段不属于任何HTTP请求的范围。当你在Configure里获取这个Scoped服务并调用SocketStart()后,应用启动完成时,根服务容器会自动释放这个Scoped实例。后续Socket收到数据流触发回调时,如果你在服务里注入了数据库上下文(同样是Scoped),这个上下文已经被释放了,自然就抛出ObjectDisposedException。

解决方案

根据你的使用场景,有两种靠谱的处理方式:

1. 将Socket服务注册为Singleton(推荐)

Socket连接通常是长期驻留的,和应用生命周期绑定,用Singleton更合理:

// ConfigureServices中修改注册方式
services.AddSingleton<ISocketIoService, SocketIo>();

然后在Configure里直接获取Singleton服务:

// Configure方法中
var socketService = app.ApplicationServices.GetRequiredService<ISocketIoService>();
socketService.SocketStart();

如果你的SocketIo服务需要用到数据库上下文(Scoped),不要在构造函数里直接注入,而是注入IServiceScopeFactory,每次处理数据时创建临时服务范围:

public class SocketIo : ISocketIoService
{
    private readonly IServiceScopeFactory _scopeFactory;

    public SocketIo(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }

    public void SocketStart()
    {
        var socket = IO.Socket("你的Socket服务地址");
        socket.On("data", async (receivedData) =>
        {
            // 创建临时服务范围,获取Scoped的数据库上下文
            using var scope = _scopeFactory.CreateScope();
            var dbContext = scope.ServiceProvider.GetRequiredService<YourDbContext>();
            
            // 转换数据并保存
            var entity = ConvertToEntity(receivedData);
            dbContext.YourEntities.Add(entity);
            await dbContext.SaveChangesAsync();
        });
    }

    // 辅助方法:将Socket数据转换为实体
    private YourEntity ConvertToEntity(dynamic receivedData)
    {
        // 这里根据你的数据结构实现转换逻辑
        return new YourEntity
        {
            // 赋值属性
        };
    }
}

这种方式既保证了Socket服务长期运行,又能每次处理数据时拿到新鲜的、未被释放的数据库上下文。

2. 在Configure中创建临时服务范围(不推荐,仅适配特殊场景)

如果一定要用Scoped的Socket服务,你需要在Configure里手动创建一个服务范围,确保服务实例在Socket运行期间不会被释放:

// Configure方法中
using var scope = app.ApplicationServices.CreateScope();
var socketService = scope.ServiceProvider.GetRequiredService<ISocketIoService>();
socketService.SocketStart();

但这种方式要注意:如果Socket服务是长期运行的,这个临时范围会一直保持,可能导致资源无法及时释放,所以更推荐第一种Singleton的方案。

额外注意点

  • 确保你的数据库上下文注册为Scoped(默认就是),这样每次通过IServiceScopeFactory创建的范围里,上下文都是独立的,不会出现并发问题。
  • 在Socket的回调里处理数据库操作时,一定要用异步方法(比如SaveChangesAsync),避免阻塞Socket的事件循环。

内容的提问来源于stack exchange,提问作者phicon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:12:31