ASP.NET 6 Web API带参数DatabaseContext依赖注入异常解决
问题场景
使用ASP.NET 6开发Web API时,相关代码及异常情况如下:
控制器代码
public AccountController(IAccountService service) { }
服务代码
public AccountService(DatabaseContext db) { }
DatabaseContext代码
public class DatabaseContext : DbContext { public DatabaseContext(string connectionString) : base() { } }
Startup.cs中的服务注册
// ... services.AddTransient<IAccountService, AccountService>(); services.AddSingleton<AccountController, AccountController>(); var connectionString = "we can get connection string here"; services.AddTransient(_ => new DatabaseContext(connectionString));
编译正常,但运行时抛出异常:
Unhandled exception. System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: API.Common.DatabaseContext Lifetime: Scoped ImplementationType: API.Common.DatabaseContext': Unable to resolve service for type 'System.String' while attempting to activate 'API.Common.DatabaseContext'.)
System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: API.Common.DatabaseContext Lifetime: Scoped ImplementationType: API.Common.DatabaseContext': Unable to resolve service for type 'System.String' while attempting to activate 'API.Common.DatabaseContext'.
System.InvalidOperationException: Unable to resolve service for type 'System.String' while attempting to activate 'API.Common.DatabaseContext'.
当DatabaseContext使用无参构造函数时一切正常,添加参数后触发上述异常,需解决带参数的DatabaseContext依赖注入问题。
解决方案
核心原因
异常根源是ASP.NET Core DI容器在服务验证阶段,检测到DatabaseContext的构造函数依赖string类型参数,但容器中未注册对应的string服务,因此抛出验证错误。
具体解决方法
方法1:使用EF Core推荐的DbContextOptions构造函数(优先选择)
这是符合框架设计的标准做法,能避免多数依赖注入冲突:
public class DatabaseContext : DbContext { public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { } }
在Startup.cs中更新注册逻辑(根据你的数据库类型调整UseSqlServer,比如PostgreSQL用UseNpgsql):
var connectionString = "we can get connection string here"; services.AddDbContext<DatabaseContext>(options => options.UseSqlServer(connectionString));
方法2:保留原构造函数,调整注册逻辑
若必须保留string参数的构造函数,可通过明确指定工厂创建逻辑,跳过容器对构造函数依赖的自动解析:
var connectionString = "we can get connection string here"; services.AddTransient<DatabaseContext>(sp => new DatabaseContext(connectionString));
注意:若之前有调用AddDbContext注册DatabaseContext,需移除该调用,避免服务描述符冲突。
额外优化:修正控制器生命周期注册
代码中把AccountController注册为Singleton是不推荐的,ASP.NET Core控制器默认是Scoped生命周期,Singleton控制器会导致后续依赖的Scoped服务(如DatabaseContext)出现生命周期不匹配问题,建议移除该行注册:
// 移除以下代码 // services.AddSingleton<AccountController, AccountController>();
内容的提问来源于stack exchange,提问作者Ming Hieu

