AddScoped注入时如何调用正确构造函数确保类默认配置生效?
问题解答
两种注册写法效果不一致,核心差异来自ASP.NET Core内置DI的构造函数选择逻辑
- 第一种写法
services.AddScoped<IHtmlSanitizer, HtmlSanitizer>()的执行逻辑:
内置DI容器会自动扫描目标类型HtmlSanitizer的所有公开构造函数,优先选择参数数量最多、且所有参数都能从当前DI容器中获取到实例的构造函数来创建对象,而非默认使用无参构造。
以你使用的HtmlSanitizer为例,该类存在多个公开构造函数,其中包含接收HtmlSanitizerOptions参数的重载,如果你的项目中恰好注册了该Options类型但没有填充默认配置,DI会直接选择这个带参构造,传入未赋值的Options实例,最终导致实例的配置字段为空。 - 第二种工厂写法的执行逻辑:
你在工厂委托中显式调用了无参构造函数new HtmlSanitizer(),完全跳过了DI的构造函数自动选择逻辑,直接执行无参构造中内置的默认配置填充逻辑,因此得到的实例字段是符合预期的非空默认值。
固定参数传参的最佳实践
工厂写法是传入固定参数的推荐方案之一,优势是实例化逻辑完全可控,你可以直接在工厂委托中自定义构造参数:
services.AddScoped<IHtmlSanitizer, HtmlSanitizer>(_ => { // 自定义配置参数 var customOptions = new HtmlSanitizerOptions { /* 你的自定义配置 */ }; return new HtmlSanitizer(customOptions); });
如果不想用工厂写法,也可以通过配置Options的方式适配第一种注册逻辑:
// 先配置默认的HtmlSanitizerOptions services.Configure<HtmlSanitizerOptions>(opt => { // 填充默认配置值 }); // 再注册服务,DI会自动传入配置好的Options services.AddScoped<IHtmlSanitizer, HtmlSanitizer>();
通用注意事项
该问题不限于HtmlSanitizer库,所有.NET Core/.NET 5+的内置DI场景都适用:当你注册的服务存在多个公开构造函数时,一定要确认DI选择的构造函数是否符合你的预期,如果需要指定构造逻辑,优先用工厂写法显式控制实例化过程。
内容的提问来源于stack exchange,提问作者Zachary Scott
相关产品推荐
相关产品推荐

