如何向WebApplicationBuilder注入无公共构造函数的单例类?
解决方案
直接使用带工厂委托的服务注册重载,手动返回你实现的单例实例即可,正确的注册代码如下:
// 注册IUserDB服务,生命周期匹配单例行为设为Singleton builder.Services.AddSingleton<IUserDB>(_ => FakeUserDB.GetInstance()); // MyUserStore的注册保持原有写法即可正常工作 builder.Services.AddTransient<IUserStore<MyUser>, MyUserStore>();
问题原因
- 你之前使用的
AddScoped<IUserDB, FakeUserDB>()是基于类型的自动实例化注册方式,这种模式下DI容器会尝试调用类的公开构造函数创建实例,但你的FakeUserDB构造函数被声明为private,容器没有访问权限,自然会出现解析失败的问题。 - 你手写的
FakeUserDB是经典的单例实现,全局只会存在一个实例,因此注册生命周期必须指定为Singleton和它的行为匹配,如果误用Scoped/Transient生命周期,可能出现实例被容器意外释放、跨作用域校验异常等问题。
可选优化方案
如果不需要严格保留手写单例的逻辑,完全可以删掉FakeUserDB里自行维护的instance字段和GetInstance()静态方法,把构造函数改为公开,直接交给DI容器托管单例生命周期,这是.NET项目里更推荐的写法,不需要自己处理单例的线程安全问题:
public class FakeUserDB : IUserDB { // 公开构造函数,容器可直接访问 public FakeUserDB() { } public string? GetPasswordHash(string username) { return "idk something"; } }
对应的注册代码更简洁:
builder.Services.AddSingleton<IUserDB, FakeUserDB>(); builder.Services.AddTransient<IUserStore<MyUser>, MyUserStore>();
内容的提问来源于stack exchange,提问作者iggy12345
相关产品推荐
相关产品推荐

