You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 21:17:41