.NET 6中DI注册Insight.Database自动接口运行报错问题
问题描述
在WebApi项目的依赖注入(DI)容器中注册Insight.Database自动接口,初始实现代码如下:
var dataString = builder.Configuration.GetConnectionString("DefaultConnection"); SqlInsightDbProvider.RegisterProvider(); var connection = new SqlConnection(dataString); builder.Services.AddTransient(thing => connection.AsParallel<IUserData>()); builder.Services.AddTransient(thing => connection.AsParallel<IRoleData>());
控制器中调用注入的接口时抛出异常,无对应公开文档说明,该实现逻辑与其他正常运行的项目代码结构一致,首次异常信息如下:
无法将类型为“Insight.Database.Providers.ProfiledDbConnection”的对象强制转换为类型“System.Data.SqlClient.SqlConnection”
后续补充的异常堆栈指向Insight.Database自动接口代理生成环节的连接类型转换逻辑。
故障原因
- 注册代码中提前创建了全局唯一的
SqlConnection实例,所有DI解析操作都复用这同一个连接对象。数据库连接是有状态资源,并发场景下单连接多线程复用本身就会触发状态错乱、连接池占用等问题。 - Insight.Database的
AsParallel<T>()方法会对传入的原生数据库连接做代理包装,第一次调用后传入的连接实例会被转换为Insight内部封装的ProfiledDbConnection类型,后续重复对这个已经被包装过的连接调用AsParallel<T>()时,内部逻辑会尝试将包装后的连接强转回原生SqlConnection类型,直接触发类型转换异常。如果项目中仅注册单个数据库接口,只会触发一次AsParallel<T>()调用,不会触发重复包装问题,这也是相同代码结构在其他单接口注册项目中可以正常运行的原因。
修复方案
调整DI注册逻辑,将连接创建过程放到服务解析的工厂委托内部,每次解析服务时生成新的连接实例再做接口代理,不要全局复用单个连接对象。修复后代码如下:
var dataString = builder.Configuration.GetConnectionString("DefaultConnection"); SqlInsightDbProvider.RegisterProvider(); builder.Services.AddTransient<IUserData>(_ => { var conn = new SqlConnection(dataString); return conn.AsParallel<IUserData>(); }); builder.Services.AddTransient<IRoleData>(_ => { var conn = new SqlConnection(dataString); return conn.AsParallel<IRoleData>(); });
- 优化建议:可以直接引入官方DI扩展包
Insight.Database.DependencyInjection,实现自动批量注册数据库接口,由扩展包自动处理连接生命周期,避免手动注册出现的生命周期配置错误。 - 注意:数据库连接不要配置为单例生命周期,使用Transient生命周期匹配WebApi请求场景即可,连接使用完成后会被自动释放回归ADO.NET连接池,不会产生连接泄漏问题。
内容的提问来源于stack exchange,提问作者Rich Bryant
相关产品推荐
相关产品推荐

