复盘一个诡异的Bug之ObjectDisposedException

起因

在集成了FurionBlazor Server项目中集成开发一个后台服务的时,莫名其妙碰见如下异常:

object-disposed-exception-1
发生异常的类是一个名为TransmissionService的在后台长期运行的服务,主要实现连接MQTT服务接受并处理消息的功能。报出异常的代码则是该类内部的一个定时器,负责断线后主动重连。

具体的异常信息如下,是一个名为EventLogInternal的对象被释放导致的。

object-disposed-exception-3

该类构造函数还有若干读配置而来的参数,不方便交由容器实现,在手动构造实例后,便用Furion.App类提供的GetService方法来获取m_Logger对象:

public TransmissionService(……)
{
    ……
    m_Logger = Furion.App.GetService<ILogger<TransmissionService>>();
    ……
}

排查

由于是第一次见到该异常,我便着手寻找复现的规律。

经过多次尝试,发现在打开或者刷新Blazor页面后,这个后台服务在记录日志时必然会报错。

object-disposed-exception-2

直觉告诉我大概率是Furion的锅,返回给我的实例内部某个对象的生命周期不对,但是翻遍Furion仓库也没找到相关Issue。

当前使用的Furion版本是一年多以前的4.8.8.40,升级到最新版能解决问题吗?

答案是否定的!

接着又想到查看Furion封装的容器中ILogger<TransmissionService>对象的生命周期,而Furion.App并未公开相关方法。

难道除了给作者提Bug外难道就没法解决了么?

解决

回到问题本身,虽然不清楚这个异常是否是由于Furion和Blazor未磨合好导致的,还是说普通的ASP.NET Core网站也会有问题,甚至我都没找出引发异常的EventLogInternal在哪里被调用,但不影响解决问题,办法也很简单,无非这三种:

  • 交由容器自动构造TransmissionService对象
  • 使用原生的容器来实现
  • 自己调试Furion源码,找到问题点,提交Bug/PR,等作者解决

综合考虑项目的进度和改动后,决定规避Furion的Bug,尝试第二种方式。

修改Main方法,在app.Run()之前获取ILogger<TransmissionService>后构造TransmissionService.

……
app.UseRouting();

app.UseHttpsRedirection();
app.MapControllers();

app.UseInject();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
……
var logger = app.Services.GetService<ILogger<TransmissionService>>();
var logger = Furion.App.GetService<ILogger<TransmissionService>>();
var transmissionService = new TransmissionService(logger, ……);
transmissionService.MessageArrived += TransmissionService_MessageArrived;
transmissionService.Run = true;
……
app.Run();

启动程序,多次刷新页面,没有异常发生。

优化

一点题外话,后面考虑将TransmissionService改造为IHostedService,由主机控制启动和停止。

最后

Furion的锅还是让作者去解决吧。

Furion作者提了Issue,回复如下:

在启动时解析服务时应该这样使用:

app.Services.GetService<ILogger<TransmissionService>>();

或者

Furion.App.GetService<ILogger<TransmissionService>>(app.Services);    // 传入 app.Services

Furion的锅已然板上钉钉,作者却不想解决,若是直接传入app.Services,我还要Furion.App.GetService何用?

2024年7月26日・天霸

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值