You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hangfire作业入队后执行失败:无参数构造函数缺失问题排查

解决Hangfire中System.MissingMethodException的问题

这个错误我太熟了,Hangfire在处理后台作业时,核心问题出在序列化/反序列化环节——当你用BackgroundJob.Enqueue提交作业时,Hangfire会把lambda里用到的所有对象(比如你的strategy实例、cpdata对象,还有_service.Engine.Summary对应的类型)序列化到数据库中,等执行作业时再反序列化回来。如果其中某个类没有可访问的无参构造函数,反序列化就会直接抛出这个异常。

下面给你几个针对性的解决方案,按优先级排序:

1. 给涉及的类添加无参构造函数

先排查你用到的几个类:

  • strategy的实际类型
  • cpdata的类型
  • 如果get方法内部依赖了其他类,也要检查这些类

如果是你自己定义的类,直接加一个public的无参构造函数就行,比如:

public class CpData {
    // 必须要有这个无参构造函数
    public CpData() {}

    // 你的其他构造函数和属性
    public CpData(int id, string name) {
        Id = id;
        Name = name;
    }

    public int Id { get; set; }
    public string Name { get; set; }
}

要是类里有必填属性,也可以在无参构造函数里给个默认值,或者后续再赋值。

2. 改用依赖注入的方式调用方法

如果你的strategy是通过依赖注入(DI)获取的实例,直接把它放到lambda里序列化是很糟糕的做法——不仅会触发构造函数问题,还可能序列化一堆不需要的依赖。

正确的做法是让Hangfire从DI容器中解析服务,然后调用方法,代码改成这样:

// 假设你的strategy实现了IStrategy接口,且已经注册到DI容器
string jobId = BackgroundJob.Enqueue<IStrategy>(s => 
    s.get(typeof(_service.Engine.Summary), cpdata));

这样Hangfire会在执行作业时自动从DI容器拿到IStrategy的实例,不需要序列化你当前的strategy对象,自然也不会要求无参构造函数了。

3. 传递简单标识符而非复杂对象

如果cpdata是个包含大量数据的复杂对象,除了序列化问题,还可能导致数据库存储的数据过大,甚至出现数据过时的情况。

建议改成传递cpdata的唯一标识符(比如ID),然后在get方法内部重新获取最新数据:

// 入队时只传ID
string jobId = BackgroundJob.Enqueue(() => 
    strategy.get(typeof(_service.Engine.Summary), cpdata.Id));

// 修改get方法,根据ID获取数据
public void get(Type targetType, int cpdataId) {
    var cpdata = _dataRepository.GetById(cpdataId);
    // 原来的业务逻辑
}

这个方法不仅能解决构造函数问题,还能让作业逻辑更健壮。

4. 配置自定义序列化器(终极方案)

如果上面的方法都不适用(比如涉及第三方类,没法修改构造函数),可以给Hangfire换个支持非无参构造函数的序列化器。比如用Newtonsoft.Json来配置:

// 在Startup的ConfigureServices方法里配置Hangfire
services.AddHangfire(config =>
{
    config.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
          .UseSimpleAssemblyNameTypeSerializer()
          .UseSerializerSettings(new JsonSerializerSettings
          {
              // 允许使用非公开的无参构造函数
              ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
              // 自定义ContractResolver处理特殊情况
              ContractResolver = new DefaultContractResolver
              {
                  IgnoreSerializableInterface = true
              }
          });
});

这样配置后,Newtonsoft.Json会尝试用类里的非公开无参构造函数来反序列化,解决构造函数缺失的问题。

内容的提问来源于stack exchange,提问作者npatel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:41:21