.NET Core 3.1中Scoped Service注入后属性为空问题排查
问题分析与解决方案
问题现象
在.NET Core 3.1环境下,IMyService是Scoped服务,MyController构造函数注入该服务后将其MyProperty设置为"Hello";ISecondaryService是Transient服务,其构造函数同样注入IMyService,但ISecondaryService中的IMyService实例的MyProperty为空。
核心原因:依赖解析顺序导致赋值时机滞后
当请求触发MyController创建时,DI容器的解析流程如下:
- 容器优先解析控制器构造函数的第一个参数
ISecondaryService:- 实例化
SecondaryService时,需要注入IMyService的Scoped实例(记为实例A),此时实例A的MyProperty为默认null,SecondaryService构造函数执行时拿到的就是这个未赋值的实例。
- 实例化
- 容器接着解析控制器的第二个参数
IMyService:- 由于是Scoped作用域,返回同一个实例A。
- 进入
MyController构造函数体后,才将实例A的MyProperty设置为"Hello"。
如果你的代码是在SecondaryService的构造函数中直接访问MyProperty,此时赋值操作还未执行,所以得到空值;但如果是在控制器的Action方法中调用SecondaryService的方法访问MyProperty,此时已经完成赋值,应该能拿到正确的"Hello"。
解决方案
方案1:提前初始化IMyService属性
将MyProperty的赋值逻辑提前到IMyService实例创建阶段,确保任何依赖它的服务拿到的都是已赋值的实例:
// Startup.cs中修改服务注册 services.AddScoped<IMyService, MyService>(sp => { var myService = new MyService(); myService.MyProperty = "Hello"; return myService; });
方案2:延迟访问MyProperty
避免在SecondaryService的构造函数中访问MyProperty,改为在实际业务方法中访问,确保此时控制器已完成赋值:
public class SecondaryService : ISecondaryService { private readonly IMyService _myService; public SecondaryService(IMyService myService) { _myService = myService; // 不要在此处访问_myService.MyProperty } public void DoBusinessLogic() { // 在此处访问MyProperty,此时已被控制器赋值 var propertyValue = _myService.MyProperty; // 结果为"Hello" } }
方案3:自定义初始化逻辑(可选)
让IMyService实现自定义初始化接口,在DI容器解析后触发初始化,确保属性提前赋值:
// 自定义初始化接口 public interface IServiceInitializer { void Initialize(); } public class MyService : IMyService, IServiceInitializer { public string MyProperty { get; set; } public void Initialize() { MyProperty = "Hello"; } } // Startup.cs中注册服务并添加初始化逻辑 services.AddScoped<IMyService, MyService>(); services.AddScoped<IServiceInitializer>(sp => (IServiceInitializer)sp.GetRequiredService<IMyService>()); // 控制器构造函数中触发初始化 public MyController(ISecondaryService secondaryService, IServiceInitializer initializer) { initializer.Initialize(); }
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

