ASP.NET Core Controller带string构造参数报依赖解析错误如何解决
在开展代码重构工作时,我将StatusController的构造函数入参从IConfiguration替换为string类型的连接字符串参数,该参数由其他控制器传入,相关实现代码如下:
StatusController.cs
public class StatusController : Microsoft.AspNetCore.Mvc.ControllerBase { protected StatusDAL status_dal; public StatusController(string connectionString) { status_dal = new StatusDAL(connectionString); } }
StatusController会被其他控制器调用,对应HVIRCalcController的实现代码如下:
HVIRCalcController.cs
public class HVIRCalcController : BaseServicesController { private readonly string _connectionString; public HVIRCalcController(IConfiguration config) { _connectionString = config.GetConnectionString("toolboxConnectionStrWPS"); } [HttpPost] public IActionResult PostTask(int service_id, [FromBody]HVIRServiceRequestParams hvir_params) { StatusAck sack = new HVIR_Calc_Engine(_connectionString).BatchCalc(hvir_params); } }
HVIRCalcEngine.cs
public class HVIR_Calc_Engine { private string _connectionString; public HVIR_Calc_Engine(string connectionString) { //this.config = config; _connectionString = connectionString; status_dal = new StatusDAL(connectionString); pg_dal = new PostgresDAL(connectionString); } public StatusAck BatchCalc(HVIRServiceRequestParams hvirparams) { StatusAck statusack = new StatusController(_connectionString).PostStatusRecord(); } }
项目运行时抛出如下错误:
Unable to resolve service for type 'System.String' while attempting to activate 'WPS_WebAPI.Controllers.StatusController'
需求是找到可行技术方案,避免将IConfiguration从HVIRCalcController开始逐层传递至StatusController,同时解决上述依赖注入报错问题。
报错核心原因是ASP.NET Core的依赖注入容器会自动尝试解析所有继承自ControllerBase的控制器构造函数参数,你给StatusController加了string类型的参数,容器不知道该注入什么值,自然会抛异常。控制器是由框架激活管理的,不应该在业务代码里手动实例化,你现在手动new控制器的写法本身就不符合ASP.NET Core的设计规范。
按下面步骤改就能解决问题,也不用逐层传配置:
- 不要把业务逻辑写在控制器里,把
StatusController里处理状态记录的逻辑抽成单独的服务类,比如IStatusService和对应实现StatusService,把原来StatusDAL的依赖放到这个服务里。public interface IStatusService { StatusAck PostStatusRecord(); } public class StatusService : IStatusService { private readonly StatusDAL _statusDal; public StatusService(IConfiguration config) { var connStr = config.GetConnectionString("toolboxConnectionStrWPS"); _statusDal = new StatusDAL(connStr); } public StatusAck PostStatusRecord() { // 迁移原来StatusController里的业务逻辑到这里 } } - 把数据访问类的依赖统一注册到DI容器,不要到处手动
new。StatusDAL、PostgresDAL都可以注册,连接字符串直接在注册的时候从配置取,不用逐层传。在Program.cs(老版本是Startup.cs)里加服务注册代码:// 注册业务服务 builder.Services.AddScoped<IStatusService, StatusService>(); // 注册DAL,注册阶段直接读取配置拿连接字符串,不需要上层传参 builder.Services.AddScoped(sp => { var config = sp.GetRequiredService<IConfiguration>(); var connStr = config.GetConnectionString("toolboxConnectionStrWPS"); return new StatusDAL(connStr); }); builder.Services.AddScoped(sp => { var config = sp.GetRequiredService<IConfiguration>(); var connStr = config.GetConnectionString("toolboxConnectionStrWPS"); return new PostgresDAL(connStr); }); // 注册计算引擎 builder.Services.AddScoped<HVIR_Calc_Engine>(); - 改造
HVIR_Calc_Engine,直接注入需要的DAL或者服务,不用接收连接字符串参数:public class HVIR_Calc_Engine { private readonly StatusDAL _statusDal; private readonly PostgresDAL _pgDal; private readonly IStatusService _statusService; public HVIR_Calc_Engine(StatusDAL statusDal, PostgresDAL pgDal, IStatusService statusService) { _statusDal = statusDal; _pgDal = pgDal; _statusService = statusService; } public StatusAck BatchCalc(HVIRServiceRequestParams hvirparams) { // 直接调用注入的服务方法,不需要手动new控制器 StatusAck statusack = _statusService.PostStatusRecord(); // 其余业务逻辑保持不变 return statusack; } } - 改造
HVIRCalcController,直接注入需要的计算引擎,不用手动读取配置传连接字符串、不用手动new引擎实例:public class HVIRCalcController : BaseServicesController { private readonly HVIR_Calc_Engine _calcEngine; public HVIRCalcController(HVIR_Calc_Engine calcEngine) { _calcEngine = calcEngine; } [HttpPost] public IActionResult PostTask(int service_id, [FromBody]HVIRServiceRequestParams hvir_params) { StatusAck sack = _calcEngine.BatchCalc(hvir_params); // 其余返回逻辑保持不变 return Ok(sack); } } - 最后清理
StatusController的构造函数,移除string类型的连接字符串参数,只保留处理HTTP请求的相关逻辑,需要的业务依赖直接注入对应服务即可。
如果只是想临时解决报错、不想做架构调整,也可以在注册控制器的时候手动指定StatusController的连接字符串参数,但这种写法不符合分层规范,后续维护成本高,不推荐长期使用。
内容的提问来源于stack exchange,提问作者Samra

