.NET Core使用SocketIOClientDotNet报错:无法访问已释放对象求助
这个报错我之前也碰到过,核心原因是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

