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

.NET Framework桌面应用中依赖注入Serilog至SettingsService的错误排查

解决.NET Framework桌面应用中Serilog ILogger依赖注入失败的问题

你遇到的问题核心是DI容器无法解析Serilog的ILogger类型,导致激活SettingsService时抛出异常。这主要是因为你的Serilog配置和Host初始化顺序有误,而且提前关闭了Logger实例,使得DI容器中没有可用的ILogger服务。

问题根源拆解

  1. 你在创建Host之前就手动实例化了Logger,还调用了Log.CloseAndFlush()直接关闭了这个实例,后续Host的UseSerilog()无法复用它
  2. 虽然调用了.UseSerilog(),但由于之前的Logger已被关闭,DI容器没有正确注册ILogger服务,自然无法注入到SettingsService中

修正方案

我们需要调整Serilog的配置逻辑,让Host统一管理Logger的生命周期,同时确保ILogger被正确注册到DI容器。

步骤1:修正App类的初始化代码

把Logger配置整合到Host的UseSerilog()中,不要提前创建和关闭Logger:

using ReceiptApplication.Services;
using Serilog;
using System.Windows;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public App()
{
    _host = Host.CreateDefaultBuilder()
        .UseSerilog((context, config) => 
        {
            config
                .MinimumLevel.Information()
                .WriteTo.Console()
                .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: true);
        })
        .ConfigureServices((context, services) =>
        {
            ConfigureServices(services);
        })
        .Build();
}

private void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ISettingsService, SettingsService>();
    services.AddSingleton<newMainWindow>();
}

protected override async void OnStartup(StartupEventArgs e)
{
    await _host.StartAsync();
    
    // 现在可以正常获取服务,ILogger会自动注入到SettingsService
    var newMainWindow = _host.Services.GetRequiredService<newMainWindow>();
    newMainWindow.Show();
    
    base.OnStartup(e);
}

protected override async void OnExit(ExitEventArgs e)
{
    // 应用退出时再关闭Logger,由Host管理生命周期
    await _host.StopAsync();
    Log.CloseAndFlush();
    base.OnExit(e);
}

步骤2:优化SettingsService的DI设计

去掉静态Log属性和手动设置方法,完全通过构造函数注入(符合DI规范):

public class SettingsService : ISettingsService
{
    private readonly ILogger _logger;

    // 构造函数注入ILogger<SettingsService>,自动关联类型上下文
    public SettingsService(ILogger<SettingsService> logger)
    {
        _logger = logger;
        _logger.Debug("SettingsService初始化完成");
    }

    public void TestLog()
    {
        _logger.Debug("这是SettingsService的测试日志");
    }

    public Settings GetSettings()
    {
        return new Settings();
    }
}

对应的ISettingsService接口也可以移除SetLog方法:

public interface ISettingsService
{
    Settings GetSettings();
    void TestLog();
}

关键细节说明

  • 用ILogger<SettingsService>代替ILogger:这是Serilog和Microsoft.Extensions.Logging集成的推荐写法,会自动为Logger添加类型名称作为日志上下文,方便后续排查问题
  • 让Host管理Logger生命周期:通过.UseSerilog()的委托配置方式,Host会负责Logger的创建和销毁,确保DI容器能正确解析ILogger<T>服务
  • 不要提前关闭Logger:应该在应用退出的OnExit方法中调用Log.CloseAndFlush(),避免Logger提前失效

这样修改后,依赖注入就能正常工作,而且完全符合DI规范,不需要再手动设置Logger了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 19:18:10