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

更新Slot模型时遇Cannot access a disposed context实例异常求助

解决DbContext已释放异常问题

异常信息

"Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'ApplicationDbContext'."

问题场景

更新Slot模型记录时触发上述异常,调试确认异常发生在执行await _context.SaveChangesAsync();阶段,无法确定DbContext被释放的原因,相关仓储层代码如下:

AddCourseToSlot方法

public async Task<Response> AddCourseToSlot(Guid slotId, Guid courseId)
{
    try
    {
        var slot = await _context.Slots.FirstOrDefaultAsync(x => x.Id == slotId);

        if (slot == null)
        {
            return new Response
            {
                message = "Sorry, this slot does not exist.",
                status = "error",
                flag = 0
            };
        }

        if (!string.IsNullOrEmpty(slot.CourseIds) && slot.CourseIds.Split(',').Contains(courseId.ToString()))
        {
            return new Response
            {
                message = "Sorry, this course has already been added.",
                status = "error",
                flag = 0
            };
        }

        var course = await _context.Courses.FirstOrDefaultAsync(x => x.Id == courseId);

        if (course == null)
        {
            return new Response
            {
                message = "Sorry, this course does not exist.",
                status = "error",
                flag = 0
            };
        }

        if (CountHours(course.Id))
        {
            return new Response
            {
                message = "Sorry, the course has exceeded its credit hours limit.",
                status = "error",
                flag = 0
            };
        }

        if (!string.IsNullOrEmpty(slot.TeacherIds) && slot.TeacherIds.Split(',').Contains(course.TeacherId.ToString()))
        {
            return new Response
            {
                message = "Sorry, the teacher already has a course in this slot.",
                status = "error",
                flag = 0
            };
        }
        
        slot.CourseIds += $",{course.Id}";
        slot.TeacherIds += $",{course.TeacherId}";
        _context.Slots.Update(slot);
        await _context.SaveChangesAsync();

        return new Response
        {
            message = "The course has been successfully added to this slot.",
            status = "success",
            flag = 1
        };
    }
    catch(Exception ex)
    {
        return new Response
        {
            message = ex.ToString(),
            status = "error",
            flag = 0
        };
    }
}

CountHours方法

private bool CountHours(Guid courseId)
{
    var ids = _context.Slots.Where(x => x.CourseIds != null).Select(x => x.CourseIds).ToList();
        
    if(ids != null)
    {
        List<Guid> courseIds = ids
        .SelectMany(x => x.Split(',', StringSplitOptions.RemoveEmptyEntries))
        .Select(guid => Guid.Parse(guid.Trim()))
        .ToList();

        int count = courseIds.Count(id => id == courseId);

        return count >= 3;
    }   

    return false;
}

解决方案

1. 检查DbContext注入生命周期

确保ApplicationDbContext在DI容器中注册为Scoped生命周期(ASP.NET Core默认配置),绝对不能用Singleton。Singleton的DbContext会在请求结束后被容器释放,后续复用必然触发异常。
注册示例:

services.AddDbContext<ApplicationDbContext>(options => 
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

2. 修复同步/异步混合操作问题

CountHours是同步方法,内部直接调用ToList()同步查询,在异步方法AddCourseToSlot中混合同步/异步操作会破坏上下文状态,导致提前释放。将其改为异步方法:

private async Task<bool> CountHours(Guid courseId)
{
    var ids = await _context.Slots.Where(x => x.CourseIds != null).Select(x => x.CourseIds).ToListAsync();
    
    if(ids == null || !ids.Any())
        return false;

    List<Guid> courseIds = ids
        .SelectMany(x => x.Split(',', StringSplitOptions.RemoveEmptyEntries))
        .Select(guid => Guid.Parse(guid.Trim()))
        .ToList();

    int count = courseIds.Count(id => id == courseId);

    return count >= 3;
}

调用处同步改为异步:

if (await CountHours(course.Id))

3. 禁止手动释放上下文

检查整个应用代码,确保没有手动调用_context.Dispose()或使用using(var context = new ApplicationDbContext())的写法。DI注入的上下文生命周期由容器管理,手动释放会导致后续操作失败。

4. 确保异步调用链全程使用await

检查调用AddCourseToSlot的上层方法,禁止使用.Result或.Wait()阻塞异步操作,这种阻塞会导致上下文被提前释放,上层方法必须全程用await调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 05:07:26