如何在.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
相关产品推荐
相关产品推荐

