ASP.NET Core 6:如何在IServicesCollection扩展方法中注入ILogger<T>
优雅在ASP.NET Core认证扩展方法中注入ILogger的方案
完全不用放弃扩展方法,以下是几种可行的优雅实现方式:
方式1:通过自定义CookieAuthenticationEvents类注入Logger
这种方式最符合依赖注入的设计原则,将日志逻辑封装到自定义Events类中,利用容器自动注入Logger:
- 定义继承自
CookieAuthenticationEvents的自定义类,构造函数注入ILogger:
public class MyCookieAuthEvents : CookieAuthenticationEvents { private readonly ILogger<MyCookieAuthEvents> _logger; public MyCookieAuthEvents(ILogger<MyCookieAuthEvents> logger) { _logger = logger; } public override Task ValidatePrincipal(CookieValidatePrincipalContext context) { _logger.LogInformation("开始验证Cookie主体"); // 你的核心认证逻辑 return base.ValidatePrincipal(context); } // 可重写其他需要日志的事件,比如OnSignIn、OnSignOut等 }
- 在扩展方法中注册该Events类,并指定给Cookie认证选项:
public static class AuthenticationBuilderExtensions { public static AuthenticationBuilder AddMyCookieAuthentication(this AuthenticationBuilder builder) { // 将自定义Events类注册到服务容器 builder.Services.AddScoped<MyCookieAuthEvents>(); return builder.AddCookie("MyCookieScheme", options => { // 指定使用自定义Events类型,容器会自动注入Logger options.EventsType = typeof(MyCookieAuthEvents); // 其他通用认证配置 options.Cookie.Name = "MyApp.Auth"; options.ExpireTimeSpan = TimeSpan.FromHours(8); // ... 其他配置项 }); } }
这种方式的优势是日志逻辑与认证逻辑解耦,完全遵循DI模式,无需手动解析服务。
方式2:在事件回调中通过HttpContext获取Logger
如果不想单独编写Events类,可在配置选项的事件回调里,借助当前请求的HttpContext获取Logger实例(请求处理阶段服务容器已完全构建):
public static class AuthenticationBuilderExtensions { public static AuthenticationBuilder AddMyCookieAuthentication(this AuthenticationBuilder builder) { return builder.AddCookie("MyCookieScheme", options => { options.Events.OnValidatePrincipal = async context => { // 通过HttpContext获取Logger var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<AuthenticationBuilderExtensions>>(); logger.LogInformation("Cookie主体验证触发"); // 你的核心认证逻辑 // ... await Task.CompletedTask; }; // 其他通用配置 options.Cookie.Name = "MyApp.Auth"; // ... }); } }
这种方式更轻量化,适合简单日志场景,但仅能在存在请求上下文的事件中使用(如所有On开头的事件),无法用于ConfigureServices阶段的初始化日志。
方式3:临时构建服务提供者获取Logger(不推荐,仅作备选)
如果确实需要在ConfigureServices阶段(比如扩展方法初始化时)记录日志,可临时构建服务提供者,但注意这会创建独立容器实例,可能与最终应用容器存在差异,仅建议用于初始化日志:
public static class AuthenticationBuilderExtensions { public static AuthenticationBuilder AddMyCookieAuthentication(this AuthenticationBuilder builder) { // 临时构建服务提供者获取LoggerFactory using var sp = builder.Services.BuildServiceProvider(); var loggerFactory = sp.GetRequiredService<ILoggerFactory>(); var logger = loggerFactory.CreateLogger<AuthenticationBuilderExtensions>(); logger.LogInformation("开始配置自定义Cookie认证"); return builder.AddCookie("MyCookieScheme", options => { // 通用认证配置 // ... }); } }
注意:该方式不适合频繁调用场景,
BuildServiceProvider会产生额外开销,且临时容器中的服务实例与最终应用容器实例并非同一个。
总结:优先选择方式1,它最贴合ASP.NET Core的DI设计理念,代码可维护性高;简单场景下方式2足够轻便;方式3仅作为特殊场景的备选。完全不需要放弃扩展方法,它正是封装通用配置的最佳实践。
内容的提问来源于stack exchange,提问作者Ryan Taylor
相关产品推荐
相关产品推荐

