起因
在集成了Furion
的Blazor Server
项目中集成开发一个后台服务的时,莫名其妙碰见如下异常:
发生异常的类是一个名为TransmissionService
的在后台长期运行的服务,主要实现连接MQTT服务接受并处理消息的功能。报出异常的代码则是该类内部的一个定时器,负责断线后主动重连。
具体的异常信息如下,是一个名为EventLogInternal
的对象被释放导致的。
该类构造函数还有若干读配置而来的参数,不方便交由容器实现,在手动构造实例后,便用Furion.App
类提供的GetService
方法来获取m_Logger
对象:
public TransmissionService(……)
{
……
m_Logger = Furion.App.GetService<ILogger<TransmissionService>>();
……
}
排查
由于是第一次见到该异常,我便着手寻找复现的规律。
经过多次尝试,发现在打开或者刷新Blazor页面后,这个后台服务在记录日志时必然会报错。
直觉告诉我大概率是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日・天霸