.NET Framework下Serilog NuGet包收敛至日志类库的实现及加载异常排查
异常产生的核心原因
- 你当前使用的.NET Framework非SDK风格项目默认采用 packages.config 模式管理NuGet包,这种模式下类库项目安装的依赖不会自动传递到主程序的输出目录:主程序编译时只会把类库本身的编译产物
Library.dll复制到自身运行目录,类库依赖的所有Serilog Sink、Enricher对应的DLL不会被自动同步,主程序运行时自然无法找到这些文件。 - Serilog 的
ReadFrom.AppSettings()实现,是通过配置文件中写入的程序集名称字符串,在主程序的运行时加载上下文里动态扫描、加载对应程序集的,不会从类库的编译路径查找DLL。只要主程序运行目录里缺少Serilog.Sinks.Console这类配置中点名的程序集,就会直接抛出FileNotFoundException。这也是为什么只有把所有Serilog相关包安装到主程序时项目才能正常运行——本质是把缺失的DLL直接放到了主程序的输出目录。 - 当前类库的初始化逻辑存在设计缺陷:虽然手动写了File Sink的配置,但App.config中所有Console、Seq、Enricher的配置完全依赖动态加载,没有在代码层面和对应程序集做编译期绑定,进一步放大了程序集加载失败的概率。
实现Serilog依赖仅存放在类库的调整方案
- 第一步,切换NuGet包管理格式
将项目默认的NuGet管理格式从 packages.config 切换为 PackageReference:在Visual Studio的NuGet通用设置中,把默认包管理格式修改为PackageReference,重新还原所有项目的NuGet包即可。这种模式下NuGet会自动计算整个引用链路的全部依赖,把类库项目用到的所有Serilog相关DLL自动复制到主程序的输出目录,不需要主程序重复安装相同的包。
切换完成后,可在类库项目的引用列表中检查所有Serilog相关依赖的属性,确保复制本地选项设置为True,避免DLL漏复制到输出目录。 - 第二步,调整Serilog初始化逻辑,消除动态加载依赖
把App.config中所有需要动态扫描程序集的配置,挪到类库的初始化代码中做显式绑定,完全去掉对App.config动态加载的依赖——动态加载本身受程序集探测路径限制,编译期的显式引用绑定不会出现运行时找不到程序集的问题。
调整后的LoggerInstaller.cs核心代码参考:using Serilog; namespace Library { static public class LoggerInstaller { static public Serilog.Core.Logger Install() { string logFileName = "MyLog.log"; var config = new LoggerConfiguration() // 对应原App.config的最小日志级别配置 .MinimumLevel.Verbose() // 显式注册Console Sink,替代App.config的动态加载逻辑 .WriteTo.Console(outputTemplate: "{Timestamp:HH:mm:ss} [{Level}] [{SourceContext}] {Message}{NewLine}{Exception}") // 显式注册Seq Sink .WriteTo.Seq("http://localhost:5341") // 保留原有File Sink参数配置 .WriteTo.File(logFileName, rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: true, fileSizeLimitBytes: 50000) // 显式注册全部Enricher,替代App.config的动态加载逻辑 .Enrich.WithThreadId() .Enrich.FromLogContext() .Enrich.WithMachineName() .Enrich.WithProcessId() .Enrich.WithMemoryUsage() .Enrich.WithAssemblyName() .Enrich.WithAssemblyVersion() .Enrich.WithProperty("Application", "SerilogTest") .CreateLogger(); Log.Logger = config; return config; } } } - 第三步,清理主程序App.config的冗余配置
把原App.config中所有serilog:using:*、serilog:write-to:*、serilog:enrich:*的节点全部删除,避免Serilog再次触发动态程序集加载逻辑,从根源上消除文件找不到的异常。
内容的提问来源于stack exchange,提问作者Q-bertsuit
相关产品推荐
相关产品推荐

