派生类共享ILogger<T>、手动创建及跨库传递ILogger<T>技术问询
关于Microsoft.Extensions.Logging的共享与实例化问题解答
1. 两个派生类共享ILogger,以及不依赖DI手动创建实例
派生类共享ILogger的几种方式
- 基类继承式共享:如果两个派生类来自同一个基类,可以在基类的构造函数中注入
ILogger<BaseClass>,派生类直接继承基类的日志实例。这样所有派生类都会使用基类的logger,日志中会标记基类的类型:public abstract class BaseService { protected readonly ILogger<BaseService> _logger; public BaseService(ILogger<BaseService> logger) { _logger = logger; } } public class DerivedService1 : BaseService { public DerivedService1(ILogger<BaseService> logger) : base(logger) { } } public class DerivedService2 : BaseService { public DerivedService2(ILogger<BaseService> logger) : base(logger) { } } - 手动传入共享实例:如果不想用基类的logger类型,也可以手动把同一个
ILogger实例传给两个派生类的构造函数。比如先创建一个共用的logger(比如ILogger<SharedLoggingMarker>,用一个空的标记类作为泛型参数),再分别传给派生类。 - 共用LoggerFactory:让两个派生类使用同一个
ILoggerFactory创建logger,这样它们的日志配置是一致的,虽然是不同的实例,但日志行为统一。
不依赖DI手动创建ILogger实例
你可以直接实例化LoggerFactory,然后用它创建指定类型的logger,完全不需要依赖注入容器:
// 1. 创建LoggerFactory并配置日志提供者 var loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); // 添加控制台输出 builder.AddDebug(); // 添加调试窗口输出 builder.SetMinimumLevel(LogLevel.Trace); // 设置最小日志级别 // 还可以添加其他提供者,比如文件、EventLog等 }); // 2. 创建指定类型的ILogger实例 ILogger<DerivedService1> logger1 = loggerFactory.CreateLogger<DerivedService1>(); ILogger<DerivedService2> logger2 = loggerFactory.CreateLogger<DerivedService2>(); // 3. 传给派生类实例 var service1 = new DerivedService1(logger1); var service2 = new DerivedService2(logger2);
如果要让两个派生类共享同一个logger实例,直接把logger1或者同一个标记类的logger传给它们即可。
2. ASP.NET Core中给.NET Standard类库传入ILogger,以及实例化依赖ILogger的类
给类库传入ILogger的正确姿势
首先,你的.NET Standard类库中的类应该通过构造函数依赖注入接收ILogger<T>,这是最符合设计原则的方式:
// .NET Standard类库中的MyClass2 public class MyClass2 { private readonly ILogger<MyClass2> _logger; // 通过构造函数接收日志实例 public MyClass2(ILogger<MyClass2> logger) { _logger = logger; } public void Execute() { _logger.LogInformation("Executing logic in MyClass2"); } }
然后在ASP.NET Core控制器中,有两种方式把logger传给这个类:
方式1:直接注入ILogger并手动传入
ASP.NET Core的DI容器可以自动解析任意ILogger<T>实例,你可以直接在控制器构造函数中注入ILogger<MyClass2>,然后手动new类库实例时传入:
public class HomeController : ControllerBase { private readonly ILogger<MyClass2> _class2Logger; public HomeController(ILogger<MyClass2> class2Logger) { _class2Logger = class2Logger; } public IActionResult Index() { // 手动创建类库实例并传入logger var myClass2 = new MyClass2(_class2Logger); myClass2.Execute(); return Ok(); } }
方式2:注入ILoggerFactory,按需创建logger
如果不想提前注入所有需要的logger,也可以注入ILoggerFactory,在需要的时候再创建对应类型的logger:
public class HomeController : ControllerBase { private readonly ILoggerFactory _loggerFactory; public HomeController(ILoggerFactory loggerFactory) { _loggerFactory = loggerFactory; } public IActionResult Index() { var class2Logger = _loggerFactory.CreateLogger<MyClass2>(); var myClass2 = new MyClass2(class2Logger); myClass2.Execute(); return Ok(); } }
实现"自动映射"的替代方案
C#本身没有内置的自动映射ILogger<T>到类实例的机制,但可以借助ASP.NET Core的DI容器来实现类似的效果:
把类库中的MyClass2注册到DI容器中:
// 在Program.cs中注册 builder.Services.AddTransient<MyClass2>();
然后控制器直接注入MyClass2,DI容器会自动为它创建并注入对应的ILogger<MyClass2>实例,完全不需要手动new:
public class HomeController : ControllerBase { private readonly MyClass2 _myClass2; public HomeController(MyClass2 myClass2) { _myClass2 = myClass2; } public IActionResult Index() { _myClass2.Execute(); return Ok(); } }
如果一定要手动new类实例,又不想每次都传logger,可以自己封装一个工厂类:
public class MyClass2Factory { private readonly ILoggerFactory _loggerFactory; public MyClass2Factory(ILoggerFactory loggerFactory) { _loggerFactory = loggerFactory; } public MyClass2 Create() { return new MyClass2(_loggerFactory.CreateLogger<MyClass2>()); } }
把工厂注册到DI,控制器注入工厂后,就可以通过factory.Create()直接创建带logger的MyClass2实例了。
内容的提问来源于stack exchange,提问作者makerofthings7
相关产品推荐
相关产品推荐

