.NET Core类库日志依赖注入配置:无需中间程序集方案问询
如何在.NET Core类库中实现可选的DI日志注入(无需中间程序集)
你的核心需求其实完全可以通过.NET Core原生的依赖注入和日志抽象来实现,不需要中间程序集,也不用在类库构造函数里加可选日志参数。关键在于利用DI的构造函数注入约定和NullLogger的自动 fallback 机制,让类库只依赖日志抽象,调用方负责配置日志服务即可。
核心思路
- 类库只需要依赖
Microsoft.Extensions.Logging.Abstractions包,通过构造函数声明对ILogger<T>的依赖,不需要自己去获取日志实例。 - 当调用方配置了日志服务(比如Serilog、Console日志等),DI容器会自动注入真实的日志实例;如果调用方没有配置日志,DI会自动注入
NullLogger<T>,完美满足“可选配置”的需求。 - 类库不需要感知DI容器的存在,也不需要任何全局静态容器,完全遵循依赖倒置原则。
修改后的代码实现
1. 类库程序集(LibraryAssembly)
类库只需要通过构造函数注入ILogger<DoIt>,不需要自己处理日志实例的获取:
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; namespace LibraryAssembly { public class DoIt { private readonly ILogger<DoIt> _logger; // 构造函数注入ILogger<T>,DI会自动处理实例,无日志配置时注入NullLogger public DoIt(ILogger<DoIt> logger = null) { // 这里的默认值只是为了兼容直接new的场景,如果完全通过DI获取实例,甚至可以去掉默认值 _logger = logger ?? NullLogger<DoIt>.Instance; } public void DoWork() { _logger.LogDebug("Doing work..."); } } }
2. 主程序集(MainAssembly)
调用方负责配置日志和DI服务,然后通过DI获取类库实例:
using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Serilog; namespace MainAssembly { class Program { static void Main() { Console.WriteLine("DI + Log Test"); // 配置Serilog日志 var serilogLogger = new LoggerConfiguration() .Enrich.FromLogContext() .MinimumLevel.Debug() .WriteTo.Console(outputTemplate: "{Timestamp:HH:mm:ss.fff} [{Level}] ({SourceContext}.{Method}) {Message}{NewLine}{Exception}") .CreateLogger(); // 配置DI服务 var services = new ServiceCollection(); // 添加日志服务,并使用Serilog作为提供方 services.AddLogging(builder => { builder.ClearProviders(); builder.AddSerilog(serilogLogger); }); // 注册类库的类型到DI容器 services.AddTransient<LibraryAssembly.DoIt>(); // 构建服务提供者 using var serviceProvider = services.BuildServiceProvider(); // 通过DI获取类库实例,日志会自动注入 var lib = serviceProvider.GetRequiredService<LibraryAssembly.DoIt>(); lib.DoWork(); // 如果调用方不想启用日志,只需要去掉AddLogging的配置即可,此时注入的是NullLogger // 类库的LogDebug调用不会抛出异常,也不会产生任何输出 Console.WriteLine("Finished."); } } }
3. NuGet包引用(主程序集)
只需要保留必要的包:
<ItemGroup> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.1" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.7" /> <PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" /> <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" /> </ItemGroup>
类库只需要引用Microsoft.Extensions.Logging.Abstractions即可。
方案优势
- 无中间程序集:完全去掉了中间的
IntermediaryAssembly,不需要全局静态容器,避免了静态依赖的问题。 - 可选日志自动支持:调用方配置日志则使用真实日志,不配置则自动使用
NullLogger,类库不需要做任何额外判断。 - 符合DI最佳实践:类库通过构造函数声明依赖,依赖抽象而非具体实现,遵循依赖倒置原则。
- 灵活性高:调用方可以自由选择日志框架(Serilog、NLog等),类库无需修改任何代码。
内容的提问来源于stack exchange,提问作者sipsorcery
相关产品推荐
相关产品推荐

