Hangfire定时汇率任务加载失败:无法找到指定版本程序集类型
Hangfire定时任务重复执行失败:程序集版本不匹配问题排查与解决
问题场景
开发了从央行获取汇率并定期写入数据库的功能,使用Hangfire实现定时执行:
- 项目运行时,Recurring Jobs标签页可见该任务,首次执行成功写入数据
- 后续定时触发时抛出类型加载错误,手动触发任务可正常运行
- 升级至.NET 8.0(或测试.NET 5.0)、更新所有NuGet包后问题依旧
- 无论使用程序集版本3.0.0.2还是4.0.0.1,系统始终尝试加载4.0.0.0版本的程序集
已完成排查:
- 确认GAC中无相关程序集
- 通过dotPeek反编译验证4.0.0.1版本程序集包含目标类型
Manager.Job.ScheduledJobs.ExchangeRateProcess.ExchangeRateJob - 开启引用的"Copy to local"选项、执行Clean-Rebuild操作无效
错误信息
System.InvalidOperationException: Recurring job can't be scheduled, see inner exception for details. ---> Hangfire.Common.JobLoadException: Could not load the job. See inner exception for the details. ---> System.TypeLoadException: Could not load type 'Manager.Job.ScheduledJobs.ExchangeRateProcess.ExchangeRateJob' from assembly 'Manager.Job.ScheduledJobs, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null'. at System.Reflection.RuntimeAssembly.GetTypeCore(String typeName, ReadOnlySpan`1 nestedTypeNames, Boolean throwOnError, Boolean ignoreCase) at System.Reflection.TypeNameParser.GetType(String typeName, ReadOnlySpan`1 nestedTypeNames, String assemblyNameIfAny) at System.Reflection.TypeNameParser.NamespaceTypeName.ResolveType(TypeNameParser& parser, String containingAssemblyIfAny) at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase) at Hangfire.Common.TypeHelper.TypeResolver(Assembly assembly, String typeName, Boolean ignoreCase) at System.Reflection.TypeNameParser.GetType(String typeName, ReadOnlySpan`1 nestedTypeNames, String assemblyNameIfAny) at System.Reflection.TypeNameParser.NamespaceTypeName.ResolveType(TypeNameParser& parser, String containingAssemblyIfAny) at System.Type.GetType(String typeName, Func`2 assemblyResolver, Func`4 typeResolver, Boolean throwOnError) at Hangfire.Common.TypeHelper.DefaultTypeResolver(String typeName) at Hangfire.Storage.InvocationData.DeserializeJob() --- End of inner exception stack trace --- at Hangfire.Storage.InvocationData.DeserializeJob() at Hangfire.RecurringJobEntity..ctor(String recurringJobId, IDictionary`2 recurringJob, ITimeZoneResolver timeZoneResolver, DateTime now) --- End of inner exception stack trace --- at Hangfire.Server.RecurringJobScheduler.ScheduleRecurringJob(BackgroundProcessContext context, IStorageConnection connection, String recurringJobId, RecurringJobEntity recurringJob, DateTime now)
解决方法
1. 清理Hangfire存储中的旧任务元数据
Hangfire会将Recurring Job的配置信息持久化到存储(如SQL Server、Redis)中,首次注册任务时记录的是旧版本程序集信息(4.0.0.0),后续程序集版本升级后,存储中的元数据未同步更新,导致调度时尝试加载旧版本类型。
- 直接在Hangfire存储中删除对应的Recurring Job记录
- 重启项目,让程序重新注册任务,生成新版本的元数据
2. 添加程序集版本绑定重定向
若不想删除旧任务,可通过配置让系统自动将旧版本程序集的请求重定向到实际使用的版本:
在项目的App.config或Web.config中添加以下配置:
<runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="Manager.Job.ScheduledJobs" publicKeyToken="null" culture="neutral" /> <bindingRedirect oldVersion="4.0.0.0" newVersion="4.0.0.1" /> </dependentAssembly> </assemblyBinding> </runtime>
3. 使用强类型方式注册Recurring Job
注册任务时采用强类型方法引用,避免字符串形式的类型名称序列化带来的版本依赖问题:
RecurringJob.AddOrUpdate<ExchangeRateJob>( "exchange-rate-job", job => job.Execute(), Cron.Hourly); // 根据实际业务需求调整定时规则
内容的提问来源于stack exchange,提问作者thejrprogrammer
相关产品推荐
相关产品推荐

