.NET 6升级后EF Core间歇性出现ConnectionString未初始化错误求助
EF Core 6.0间歇性抛出「ConnectionString未初始化」异常的解决
问题背景
升级Azure Function运行时至v4,项目迁移到.NET 6,替换System.Data.SqlClient为Microsoft.Data.SqlClient,同时将Microsoft.EntityFrameworkCore从2.1.4升级到6.0.10后,调用EF Core查询时间歇性出现以下异常:
System.InvalidOperationException: The ConnectionString property has not been initialized.
涉及代码片段:
public async Task<Common.Entities.Delivery> GetNotificationDeliveryByRequestIdClientId(string notificationRequestId, int clientId) { Common.Entities.Delivery deliveryContext = null; try { deliveryContext = await (from delivery in _context.Delivery where delivery.NotificationRequestId == notificationRequestId where delivery.ClientId == clientId select delivery).FirstOrDefaultAsync(); } catch (Exception ex) { Logger.LogCritical(ex, $"{DeliveryComponent}.{nameof(GetNotificationDeliveryByRequestIdClientId)}.Exception"); } return deliveryContext; }
Repository构造函数:
public NotificationDeliveryRepository(NotificationsDeliveryContext deliveryContext) { _context = deliveryContext; } public NotificationDeliveryRepository(string deliverySqlConnStr, ILogger logger) { var options = new DbContextOptionsBuilder<NotificationsDeliveryContext>().UseSqlServer(deliverySqlConnStr) .Options; _context = new NotificationsDeliveryContext(options); Logger = logger ?? throw new ArgumentException(nameof(logger)); }
可能的原因
- DbContext生命周期错误:Azure Function为无状态服务,若DbContext被注册为单例(Singleton),会导致连接池异常或连接字符串被意外覆盖/清空。EF Core的DbContext设计为短生命周期,需按请求创建和释放。
- 连接字符串为空:
deliverySqlConnStr可能在某些场景下未正确加载(如配置刷新、环境变量读取失败),导致创建DbContext时未初始化连接字符串。 - DbContext构造函数配置冲突:
NotificationsDeliveryContext若存在无参构造函数或未正确处理DbContextOptions,会覆盖传入的连接字符串配置。 - 连接泄漏:手动创建的DbContext未及时释放,导致连接池耗尽,间接引发连接字符串未初始化的错误(实际为连接获取失败的表现)。
解决方法
1. 确保DbContext生命周期正确
在Azure Function的依赖注入中,将NotificationsDeliveryContext注册为Scoped(按请求生命周期),避免单例:
// Program.cs/Startup.cs builder.Services.AddDbContext<NotificationsDeliveryContext>(options => options.UseSqlServer(Environment.GetEnvironmentVariable("DeliverySqlConnStr")));
之后通过构造函数注入NotificationsDeliveryContext到Repository,而非手动创建实例。
2. 添加连接字符串空值校验
在手动创建DbContext的构造函数中,先校验连接字符串是否有效:
public NotificationDeliveryRepository(string deliverySqlConnStr, ILogger logger) { if (string.IsNullOrWhiteSpace(deliverySqlConnStr)) throw new ArgumentNullException(nameof(deliverySqlConnStr), "连接字符串不能为空"); var options = new DbContextOptionsBuilder<NotificationsDeliveryContext>() .UseSqlServer(deliverySqlConnStr) .Options; _context = new NotificationsDeliveryContext(options); Logger = logger ?? throw new ArgumentException(nameof(logger)); }
3. 规范DbContext构造函数
确保NotificationsDeliveryContext仅保留接受DbContextOptions的构造函数,避免无参构造函数导致配置丢失:
public class NotificationsDeliveryContext : DbContext { public NotificationsDeliveryContext(DbContextOptions<NotificationsDeliveryContext> options) : base(options) { } // 删除或禁用无参构造函数 // public NotificationsDeliveryContext() { } }
4. 及时释放DbContext
若必须手动创建DbContext,使用using语句确保实例被正确释放:
using var context = new NotificationsDeliveryContext(options); var delivery = await context.Delivery .Where(d => d.NotificationRequestId == notificationRequestId && d.ClientId == clientId) .FirstOrDefaultAsync();
5. 验证配置加载
检查Azure Function的环境变量或配置文件,确保连接字符串在所有实例中都能稳定加载。可在函数启动时添加日志,确认连接字符串已正确读取(注意不要输出明文)。
内容的提问来源于stack exchange,提问作者likhita yadama
相关产品推荐
相关产品推荐

