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

.NET 8中服务调用DbContext报错,如何在控制器外使用上下文?

在.NET 8中控制器外使用DbContext的问题排查与解决

问题描述

在.NET 8环境下,API控制器中使用SomeContext可正常工作,但在CqcService中注入并使用该上下文时,抛出数据库连接错误:

Microsoft.EntityFrameworkCore.Database.Connection[20004]
使用服务器'(localdb)\mssqllocaldb'上的数据库'SomeContext'的连接时发生错误。

相关配置与代码:

  • 连接字符串:
"ConnectionStrings": {
    "SomeContext": "Server=(localdb)\\mssqllocaldb;Database=SomeContext;Trusted_Connection=True;MultipleActiveResultSets=true"
}
  • Program.cs中的DbContext注册:
builder.Services.AddDbContext<SomeContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("SomeContext") ?? throw new InvalidOperationException("Connection string 'SomeContext' not found.")));
  • 报错的服务代码:
private readonly SomeContext _context;

public CqcService(SomeContext context)
{
    _context = context;
}

public async Task<Provider?> GetProvider(string id)
{
    var dbProvider = await _context.Provider.SingleOrDefaultAsync(x => x.ProviderId == id);

    return dbProvider;
}

解决方案

1. 确保服务已注册到依赖注入容器

控制器能正常注入DbContext说明上下文注册无问题,但CqcService本身需要被注册到DI容器才能实现构造函数注入。在Program.cs中添加服务注册:

// 根据业务需求选择Scoped/Transient/Singleton,注意与DbContext生命周期匹配
builder.Services.AddScoped<CqcService>();

2. 检查服务与DbContext的生命周期兼容性

默认AddDbContext注册的DbContext为Scoped生命周期(每个请求创建一个实例)。如果CqcService被注册为Singleton,注入Scoped的DbContext会导致上下文在请求结束后被释放,后续使用时触发连接错误。

解决方式:

  • 将服务改为Scoped或Transient(推荐与DbContext生命周期一致):
builder.Services.AddScoped<CqcService>();
// 或
builder.Services.AddTransient<CqcService>();
  • 若必须使用Singleton服务,改用AddDbContextFactory创建上下文实例:
// 注册DbContext工厂
builder.Services.AddDbContextFactory<SomeContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("SomeContext")));

然后在服务中注入工厂,使用时创建上下文:

private readonly IDbContextFactory<SomeContext> _contextFactory;

public CqcService(IDbContextFactory<SomeContext> contextFactory)
{
    _contextFactory = contextFactory;
}

public async Task<Provider?> GetProvider(string id)
{
    using var context = _contextFactory.CreateDbContext();
    var dbProvider = await context.Provider.SingleOrDefaultAsync(x => x.ProviderId == id);
    return dbProvider;
}

3. 避免同步调用异步方法导致死锁

如果服务方法被同步代码调用(如使用.Result或.Wait()),可能引发线程死锁,进而导致数据库连接异常。确保全程使用异步调用:

// 错误示例:同步调用异步方法
var provider = cqcService.GetProvider(id).Result;

// 正确示例:使用await
var provider = await cqcService.GetProvider(id);

4. 验证DbContext的定义

检查SomeContext类是否正确继承DbContext,且未在OnConfiguring方法中硬编码连接字符串覆盖配置:

public class SomeContext : DbContext
{
    public SomeContext(DbContextOptions<SomeContext> options) : base(options)
    {
    }

    // 不要在OnConfiguring中硬编码连接字符串,除非是开发环境临时测试
    // protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    // {
    // }

    public DbSet<Provider> Provider { get; set; }
}

5. 检查LocalDB运行状态

若以上配置均无问题,可排查LocalDB本身:

  • 打开命令提示符,执行sqllocaldb info查看实例状态
  • 若实例未运行,执行sqllocaldb start mssqllocaldb启动
  • 必要时删除并重建实例:sqllocaldb delete mssqllocaldb → sqllocaldb create mssqllocaldb

内容的提问来源于stack exchange,提问作者SmallWorld

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:42:42