You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 6:如何在IServicesCollection扩展方法中注入ILogger<T>

优雅在ASP.NET Core认证扩展方法中注入ILogger的方案

完全不用放弃扩展方法,以下是几种可行的优雅实现方式:

方式1:通过自定义CookieAuthenticationEvents类注入Logger

这种方式最符合依赖注入的设计原则,将日志逻辑封装到自定义Events类中,利用容器自动注入Logger:

  1. 定义继承自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等
}
  1. 在扩展方法中注册该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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 20:42:53