如何在Serilog+Autofac下将ILogger<T>注入仅需ILogger的构造函数?
解决方案:使用Serilog + Autofac注入对应类的ILogger(而非ILogger)
核心思路
通过Autofac的自定义参数解析逻辑,在构造函数注入时自动将ILogger参数替换为当前类对应的ILogger<T>实例,避免重复编写泛型声明。本质是利用Autofac的注册拦截能力,根据目标类型动态生成对应日志实例。
所需依赖包
根据项目类型安装对应包:
- ASP.NET Core 6:
Autofac.Extensions.DependencyInjection、Serilog.AspNetCore、Serilog.Sinks.Console - .NET 6控制台应用:
Autofac、Serilog、Serilog.Sinks.Console、Microsoft.Extensions.Logging
场景1:ASP.NET Core 6配置
在Program.cs中替换默认DI容器为Autofac,并添加日志注入规则:
using Autofac; using Autofac.Extensions.DependencyInjection; using Serilog; var builder = WebApplication.CreateBuilder(args); // 1. 配置Serilog builder.Host.UseSerilog((context, config) => { config.WriteTo.Console() .ReadFrom.Configuration(context.Configuration); }); // 2. 替换为Autofac容器工厂 builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); // 3. 配置Autofac注册规则 builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder => { // 注册当前程序集下所有需要注入日志的类型 containerBuilder.RegisterAssemblyTypes(typeof(Program).Assembly) .AsSelf() .WithParameter( (pi, ctx) => pi.ParameterType == typeof(ILogger), (pi, ctx) => ctx.Resolve<ILoggerFactory>().CreateLogger(pi.Member.DeclaringType) ); }); // 其他服务注册... var app = builder.Build(); // 中间件配置... app.Run();
场景2:.NET 6控制台应用配置
手动构建Autofac容器并集成Serilog:
using Autofac; using Microsoft.Extensions.Logging; using Serilog; // 1. 初始化Serilog Log.Logger = new LoggerConfiguration() .WriteTo.Console() .CreateLogger(); // 2. 创建LoggerFactory,关联Serilog var loggerFactory = LoggerFactory.Create(builder => { builder.AddSerilog(); }); // 3. 构建Autofac容器 var containerBuilder = new ContainerBuilder(); // 注册LoggerFactory containerBuilder.RegisterInstance(loggerFactory).As<ILoggerFactory>(); // 注册目标类型并添加日志注入规则 containerBuilder.RegisterAssemblyTypes(typeof(Program).Assembly) .AsSelf() .WithParameter( (pi, ctx) => pi.ParameterType == typeof(ILogger), (pi, ctx) => loggerFactory.CreateLogger(pi.Member.DeclaringType) ); using var container = containerBuilder.Build(); // 4. 验证注入 var myClass = container.Resolve<MyClass>(); myClass.DoSomething(); // 关闭Serilog Log.CloseAndFlush();
验证代码(目标类)
按照期望的方式编写类,构造函数仅声明ILogger:
public class MyClass { private readonly ILogger _logger; public MyClass(ILogger logger) { _logger = logger; _logger.LogInformation("MyClass构造函数初始化"); } public void DoSomething() { _logger.LogInformation("执行DoSomething方法"); } }
关键说明
- 参数解析逻辑:
WithParameter的两个委托分别用于判断参数是否为ILogger,以及动态创建对应类的ILogger实例(通过ILoggerFactory.CreateLogger传入当前类的类型)。 - 范围控制:如果不需要对所有类应用该规则,可以修改
RegisterAssemblyTypes的过滤条件(比如指定命名空间、标记特定接口等)。 - Serilog集成:确保
ILoggerFactory正确关联Serilog,这样生成的ILogger实例会使用Serilog作为底层日志实现。
内容的提问来源于stack exchange,提问作者Leyu
相关产品推荐
相关产品推荐

