如何在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为例:
- 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(); }
- 窗体中注入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
相关产品推荐
相关产品推荐

