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

.NET Core Worker服务中自定义类Serilog依赖注入后Logger为空的问题排查

问题根源分析

你遇到的问题核心很明确:JsonConvert.DeserializeObject是直接通过反射创建MyCustomProduct实例的,不会经过.NET Core的依赖注入(DI)容器。这意味着你的构造函数里的ILogger<MyCustomProduct>参数不会被DI容器自动填充,自然就会是null,调用日志方法时就会抛出空引用异常。

下面给你几种可行的解决方案,你可以根据自己的需求选择:


方案一:使用Serilog全局静态日志类(最简单)

既然你已经在Program.cs里配置了全局的Log.Logger,完全可以直接在MyCustomProduct里使用Serilog提供的静态Log类,不需要通过构造函数注入。这种方法最简单,不需要改动DI配置或反序列化逻辑。

修改MyCustomProduct类:

public class MyCustomProduct
{
    // 移除构造函数注入的ILogger
    public void YourMethod()
    {
        // 直接使用Serilog的静态Log类
        Log.Information("日志内容:从MyCustomProduct输出");
        // 如果需要区分上下文,也可以创建一个Logger实例(依然不需要DI)
        var logger = Log.ForContext<MyCustomProduct>();
        logger.Debug("带上下文的调试日志");
    }
}

方案二:让Json.NET使用DI容器创建实例

如果你坚持要通过构造函数注入ILogger,可以配置Json.NET在反序列化时使用DI容器来解析构造函数参数。步骤如下:

  1. 在Worker中注入IServiceProvider:
private readonly ILogger<Worker> _logger;
private readonly IServiceProvider _serviceProvider;

public Worker(ILogger<Worker> logger, IServiceProvider serviceProvider)
{
    _logger = logger;
    _serviceProvider = serviceProvider;
}
  1. 将MyCustomProduct注册到DI容器:
    在ConfigureServices方法中添加:
services.AddTransient<MyCustomProduct>();
  1. 自定义Json.NET的ContractResolver:
    这个Resolver会让Json.NET使用DI容器来创建对象实例:
public class DiContractResolver : DefaultContractResolver
{
    private readonly IServiceProvider _serviceProvider;

    public DiContractResolver(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        var contract = base.CreateObjectContract(objectType);
        // 替换默认的实例创建逻辑,改为从DI容器获取
        contract.DefaultCreator = () => _serviceProvider.GetRequiredService(objectType);
        return contract;
    }
}
  1. 使用自定义Resolver反序列化:
var settings = new JsonSerializerSettings
{
    ContractResolver = new DiContractResolver(_serviceProvider)
};
MyCustomProduct cProduct = JsonConvert.DeserializeObject<MyCustomProduct>(response.Content, settings);

这样反序列化出来的MyCustomProduct实例,其构造函数的ILogger参数就会被DI容器正确注入了。


方案三:反序列化后手动注入Logger

如果不想修改Json.NET的配置,可以在反序列化完成后,手动从DI容器获取Logger并赋值给MyCustomProduct:

  1. 修改MyCustomProduct,添加Logger属性:
public class MyCustomProduct
{
    public ILogger<MyCustomProduct> Logger { get; set; }

    // 添加无参构造函数,让JsonConvert能创建实例
    public MyCustomProduct() { }

    // 或者保留带参构造函数,同时加无参构造函数
    public MyCustomProduct(ILogger<MyCustomProduct> logger)
    {
        Logger = logger;
    }

    public void YourMethod()
    {
        Logger?.LogInformation("日志内容:从MyCustomProduct输出");
    }
}
  1. 在Worker中手动赋值Logger:
// 先反序列化
MyCustomProduct cProduct = JsonConvert.DeserializeObject<MyCustomProduct>(response.Content);
// 从DI容器获取Logger并赋值
cProduct.Logger = _serviceProvider.GetRequiredService<ILogger<MyCustomProduct>>();

方案推荐

  • 如果你的日志需求比较简单,方案一是最省心的,不需要改动DI或反序列化逻辑,直接用Serilog的静态类即可。
  • 如果你的项目严格遵循依赖注入的设计原则,方案二更符合规范,但需要额外的配置。
  • 方案三适合快速临时解决问题,代码改动最小,但不够优雅。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 00:52:41