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

如何在.NET 6中优化含ILogger依赖的参数化全局过滤器DI

全局过滤器依赖注入优化:避免重复创建单例服务

问题场景

我在Program.cs中注册带参数的全局Action过滤器时,通过BuildServiceProvider()获取Logger实例,代码如下:

builder.Services.AddControllersWithViews(options =>
{
    // 该行触发警告
    var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<ResponseHeaderActionFilter>>();

    options.Filters.Add(new ResponseHeaderActionFilter(logger, "X-Global-State", "Started"));
});

收到警告提示:

"Calling BuildServiceProvider from application code results in additional copy of Singleton services being created. Consider alternatives such as DI services as parameters to configure."

我的ResponseHeaderActionFilter类构造函数依赖Serilog的ILogger<T>,代码如下:

namespace ContactsManager.Filters.ActionFilters
{
    public class ResponseHeaderActionFilter : IActionFilter
    {
        private readonly ILogger<ResponseHeaderActionFilter> _logger;
        private readonly string _key;
        private readonly string _value;
        
        public ResponseHeaderActionFilter(ILogger<ResponseHeaderActionFilter> logger, string key, string value)
        {
            _logger = logger;
            _key = key;
            _value = value;
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            _logger.LogInformation("{FilterName}.{MethodName} executed", nameof(ResponseHeaderActionFilter), nameof(OnActionExecuted));
            context.HttpContext.Response.Headers[_key] = _value;
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            _logger.LogInformation("{FilterName}.{MethodName} executed", nameof(ResponseHeaderActionFilter), nameof(OnActionExecuting));
        }
    }
}

解决方案

方法一:使用TypeFilterAttribute注册

TypeFilterAttribute会自动从DI容器解析过滤器的依赖项,同时允许传递自定义参数。修改Program.cs中的注册逻辑:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new TypeFilterAttribute(typeof(ResponseHeaderActionFilter))
    {
        Arguments = new object[] { "X-Global-State", "Started" }
    });
});
  • 容器会负责注入ILogger<ResponseHeaderActionFilter>
  • Arguments数组中的值会按顺序传递给过滤器构造函数的剩余参数

方法二:先注册过滤器为服务,再添加到全局过滤器

先将过滤器注册为Scoped服务(符合Action过滤器的生命周期),通过工厂方法注入依赖和自定义参数:

// 注册过滤器服务
builder.Services.AddScoped<ResponseHeaderActionFilter>(sp => 
    new ResponseHeaderActionFilter(
        sp.GetRequiredService<ILogger<ResponseHeaderActionFilter>>(), 
        "X-Global-State", 
        "Started"
    )
);

// 添加到全局过滤器集合
builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add<ResponseHeaderActionFilter>();
});
  • 这种方式完全利用DI容器的生命周期管理,避免手动创建实例导致的单例重复
  • 依赖项从主容器解析,保证单例服务的唯一性

内容的提问来源于stack exchange,提问作者user3348988

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 15:22:51