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

如何在C# WinForms应用中引用ILogger实现跨模块日志记录

问题分析与解决方案

当前日志不写入的原因

你的日志未写入文件,核心问题是**StreamWriter和LoggerFactory被包裹在局部using块中**:当代码执行完using块后,StreamWriter会被立即释放,即使Log方法调用了Flush,整个日志上下文已被销毁,导致日志无法持久化。


修正日志初始化代码

将日志组件的生命周期与应用程序绑定,避免提前释放资源。在Program.cs中全局初始化:

// Program.cs 全局变量
private static ILoggerFactory _loggerFactory;
private static StreamWriter _logFileWriter;

static void Main()
{
    // 日志文件路径:应用程序根目录下的app.log
    string logFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "app.log");
    // 不要用using包裹,避免提前释放;开启AutoFlush自动刷新缓冲区
    _logFileWriter = new StreamWriter(logFilePath, append: true) { AutoFlush = true };

    // 初始化LoggerFactory
    _loggerFactory = LoggerFactory.Create(builder =>
    {
        builder.AddProvider(new CustomFileLoggerProvider(_logFileWriter));
    });

    // 启动主窗体
    Application.Run(new MainForm());

    // 应用退出时统一释放资源
    _logFileWriter?.Dispose();
    _loggerFactory?.Dispose();
}

在应用全局引用ILogger的两种方式

方式1:通过全局LoggerFactory创建实例

直接在需要日志的窗体/类中调用全局_loggerFactory创建实例,适合小型项目快速实现:

// 示例:主窗体中使用日志
public class MainForm : Form
{
    private readonly ILogger _logger;

    public MainForm()
    {
        InitializeComponent();
        // 用当前类名作为日志分类,便于区分日志来源
        _logger = Program._loggerFactory.CreateLogger(nameof(MainForm));
    }

    private void btnOperation_Click(object sender, EventArgs e)
    {
        // 记录普通信息
        _logger.LogInformation("用户点击了操作按钮");
        
        // 记录异常日志
        try
        {
            int.Parse("非数字字符串");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "字符串解析失败");
        }
    }
}

方式2:依赖注入(推荐)

如果是中型以上项目,推荐用依赖注入管理日志实例,解耦性更强。以.NET自带的ServiceCollection为例:

  1. Program.cs中注册服务
static void Main()
{
    string logFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "app.log");
    var logFileWriter = new StreamWriter(logFilePath, append: true) { AutoFlush = true };
    
    var loggerFactory = LoggerFactory.Create(builder =>
    {
        builder.AddProvider(new CustomFileLoggerProvider(logFileWriter));
    });

    // 构建服务容器
    var services = new ServiceCollection();
    // 注册LoggerFactory为单例
    services.AddSingleton(loggerFactory);
    // 注册泛型ILogger<T>,支持按类注入
    services.AddTransient(typeof(ILogger<>), typeof(Logger<>));
    // 注册主窗体
    services.AddTransient<MainForm>();

    var serviceProvider = services.BuildServiceProvider();

    // 从容器获取主窗体并启动
    var mainForm = serviceProvider.GetRequiredService<MainForm>();
    Application.Run(mainForm);

    // 应用退出时清理资源
    logFileWriter?.Dispose();
}
  1. 窗体中注入ILogger
public class MainForm : Form
{
    private readonly ILogger<MainForm> _logger;

    // 构造函数自动注入ILogger<MainForm>
    public MainForm(ILogger<MainForm> logger)
    {
        InitializeComponent();
        _logger = logger;
    }

    private void btnSave_Click(object sender, EventArgs e)
    {
        _logger.LogInformation("数据保存操作执行完成");
    }
}

CustomFileLogger小优化

如果需要支持日志作用域,可以修改BeginScope方法:

// 新增简单的作用域实现类
public class CustomScope : IDisposable
{
    private readonly StreamWriter _writer;
    private readonly string _scopeName;

    public CustomScope(StreamWriter writer, string scopeName)
    {
        _writer = writer;
        _scopeName = scopeName;
        _writer.WriteLine($"[Scope Start] {_scopeName}");
    }

    public void Dispose()
    {
        _writer.WriteLine($"[Scope End] {_scopeName}");
    }
}

// 修改CustomFileLogger的BeginScope方法
public IDisposable BeginScope<TState>(TState state)
{
    return new CustomScope(_logFileWriter, state.ToString());
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 23:48:14