ASP.NET Web Site Project 中集成 Hangfire 并实现图片/视频压缩后台任务
今天在 ASP.NET Web Site Project 中集成 Hangfire 并实现图片/视频压缩后台任务,遇到了一系列技术挑战,最终全部解决。下面是关键问题与解决方法的总结:
一、Hangfire 集成与启动问题
问题1:OWIN 启动类无法被发现,/hangfire 返回 404
-
现象:访问
/hangfire时出现 404,Startup.cs的Configuration方法断点未命中。 -
原因:Web Site Project 中 OWIN 自动发现机制不可靠,且
Global.asax中Application_Start未正确配置。 -
解决:
-
放弃 OWIN 自动发现,改用
Global.asax的Application_Start手动配置 Hangfire 存储并启动BackgroundJobServer。 -
删除
App_Code下多余的Global.asax,只保留根目录下的Global.asax。 -
在
web.config中添加<add key="owin:AutomaticAppStartup" value="false" />禁用 OWIN 自动发现。
-
问题2:Current JobStorage instance has not been initialized yet
-
现象:创建
BackgroundJobServer时抛出此异常。 -
原因:未在
BackgroundJobServer之前调用GlobalConfiguration.Configuration.UseSqlServerStorage。 -
解决:确保在
Application_Start中先配置存储,后启动服务器。
问题3:Application_Start 未执行,日志未生成
-
现象:
Global.asax中的Application_Start没有输出日志。 -
原因:IIS 应用程序池未设置为
AlwaysRunning,或网站未预加载。 -
解决:
-
设置应用程序池:
启动模式=AlwaysRunning,闲置超时=0。 -
设置网站:
预加载已启用=True。
-
问题4:Hangfire 任务卡在 Enqueued 状态不执行
-
现象:数据库
HangFire.Job表中有任务但状态一直是Enqueued。 -
原因:
BackgroundJobServer未成功启动或被 IIS 回收。 -
解决:通过上述 IIS 配置保证服务器常驻,同时在
Application_Start中正确启动服务器。
二、图片压缩问题(SkiaSharp)
问题5:Unable to load library 'libSkiaSharp'
-
现象:压缩图片时抛出
DllNotFoundException。 -
原因:SkiaSharp 依赖原生库
libSkiaSharp.dll,Web Site Project 不会自动将其复制到bin目录。 -
解决:
-
安装
SkiaSharp.NativeAssets.Win32(或 Win64)NuGet 包。 -
手动从包目录(
~/.nuget/packages/skiasharp.nativeassets.win32/版本号/runtimes/win-{x86|x64}/native/)找到libSkiaSharp.dll。 -
将其复制到网站的
bin目录下。 -
确保应用程序池位数与 DLL 位数匹配。
-
问题6:HttpContext.Current 在后台任务中为 null,导致日志写入失败
-
现象:
WriteLog方法中使用HttpContext.Current.Request.PhysicalApplicationPath引发“请求在此上下文中不可用”。 -
原因:Hangfire 后台任务执行时没有 HTTP 上下文。
-
解决:将
WriteLog中的路径获取改为AppDomain.CurrentDomain.BaseDirectory或HostingEnvironment.ApplicationPhysicalPath。
三、视频压缩问题(FFmpeg)
问题7:FFmpeg 压缩后视频体积变大且不清晰
-
现象:3.76MB 视频压成了 5.76MB,画质下降。
-
原因:使用了
-preset veryfast导致压缩效率低,且原始视频可能已高度压缩,重新编码时反而膨胀。 -
解决:
-
改用
-preset medium或-preset slow获得更好压缩率。 -
调整
-crf值(如 23 → 28)增大压缩力度。 -
可选添加
-vf scale=1280:-2降低分辨率。
-
问题8:FFmpeg 共享版导致文件占用,删除/移动失败
-
现象:压缩完成后无法删除原文件或移动临时文件,提示文件被占用。
-
原因:使用的 FFmpeg 为共享版(
--enable-shared),依赖多个 DLL,进程退出后文件句柄未及时释放。 -
解决:
-
换用静态编译版 FFmpeg(从 gyan.dev 下载),只需一个
ffmpeg.exe。 -
在代码中添加
Thread.Sleep(100)和文件操作重试循环。 -
使用
Process时正确等待退出、关闭进程、异步读取错误流。
-
问题9:FFmpeg 路径与部署
-
现象:服务器上 FFmpeg 路径问题。
-
解决:
-
推荐将静态版
ffmpeg.exe放在网站bin目录下,代码中使用绝对路径或AppDomain.CurrentDomain.BaseDirectory + "bin/ffmpeg.exe"。 -
或者设置系统环境变量,但 IIS 可能无法继承,不如直接指定路径可靠。
-
四、配置与监控完善
-
连接字符串:统一在
web.config的<connectionStrings>中配置,供 Hangfire 和业务代码共用。 -
日志系统:改造
WriteLog使其不依赖HttpContext,并在App_Data或指定目录输出。 -
Hangfire Dashboard:虽然 Web Site Project 中 OWIN 启动困难,但最终通过
Global.asax手动启动服务器,Dashboard 仍可访问(需正确配置 OWIN 启动类或使用第三方方案,用户最终放弃 Dashboard,改用数据库查询和自定义日志监控)。 -
任务重试:Hangfire 默认自动重试,可通过
[AutomaticRetry]特性调整。
最终成果
-
✅ Hangfire 后台任务稳定运行,任务不再卡在
Enqueued。 -
✅ 图片压缩功能正常,原生库正确加载。
-
✅ 视频压缩功能正常,参数优化后体积合理,文件操作不再报错。
-
✅ 日志系统健壮,不依赖 HTTP 上下文。
-
✅ IIS 配置优化,应用程序池始终运行,后台任务不因空闲而停止。
经验教训
-
Web Site Project 对 OWIN 支持不友好,尽量使用
Global.asax手动启动 Hangfire。 -
SkiaSharp 需要手动部署原生库,不能仅依赖 NuGet 自动复制。
-
FFmpeg 优先使用静态编译版,避免 DLL 依赖和文件锁定问题。
-
后台任务中避免使用
HttpContext.Current,改用AppDomain或HostingEnvironment。 -
IIS 必须配置为
AlwaysRunning+ 预加载,否则后台服务会被回收。 -
文件操作要添加重试和延时,以应对进程释放句柄的延迟。
今天的问题虽然曲折,但最终全部攻克。如果以后遇到类似需求,可以快速参考这套方案。

浙公网安备 33010602011771号