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

如何防止注入的DbContext被释放?遇ObjectDisposedException

DbContext连续调用触发ObjectDisposedException的解决方法

我创建了ObjectBuilder类,通过构造函数注入dbContext并将其设为只读属性。类中包含多个使用dbContext的方法,比如CreateOrUpdateObject。在API控制器中实例化ObjectBuilder后,连续三次调用CreateOrUpdateObject方法:第一次执行正常,但第二次触发了ObjectDisposedException。我理解该异常含义,但未手动释放上下文或使用using语句,无法解决单次方法执行后上下文就被释放、后续方法无法运行的问题,恳请告知如何避免DbContext被释放以支持链式调用。


ObjectBuilder类代码片段

class ObjectBuilder
{
    readonly GuidObjectBuilder _guidObjectBuilder;
    readonly projectviewerContext _db;
    bool UpdatedGuidsArray { get; set; }
    int UpdatedObjectCount { get; set; }
    int CreatedObjectCount { get; set; }
    ProjectObjects ActiveObject { get; set; }

    public ObjectBuilder(GuidObjectBuilder guidObjectBuilder, projectviewerContext db)
    {
        this._guidObjectBuilder = guidObjectBuilder;
        this._db = db;
        this.UpdatedGuidsArray = false;
        this.UpdatedObjectCount = 0;
        this.CreatedObjectCount = 0;
    }

    public async Task<dynamic> CreateOrUpdateObject(string projectName, string tag, string pidClass, string guId, string fileName)
    {
        //SEND ONE ENTRY RETURNS A PROJECT_OBJECT MODEL
        if (this._db == null) throw new ArgumentNullException("The object builder class has not been set a database. Set the object with a database");
        try
        {
            //Check for an initial entry
            List<ProjectObjects> matchingProjectObjects = (from data in this._db.ProjectObjects.ToList()
                                                            where data.ProjectName == projectName &&
                                                            data.Tag == tag
                                                            select data).ToList();

            if (matchingProjectObjects.Any())
            {
                this.ActiveObject = this.UpdateProjectObject(matchingProjectObjects[0], pidClass, guId, fileName);
                this._db.Update(this.ActiveObject);
                this.UpdatedObjectCount++;
            }
            else
            {
                this.ActiveObject = this.CreateProjectObject(projectName, tag, pidClass, guId, fileName);
                this._db.Add(this.ActiveObject);
                this.CreatedObjectCount++;
            }
            await this._db.SaveChangesAsync();
            if (this.UpdatedGuidsArray)
            {
                //Add new guid
                await this._guidObjectBuilder.CreateOrUpdateUponModelOpen(this.ActiveObject.Id, guId, fileName);
            }
            this.UpdatedGuidsArray = false;
            return this.ActiveObject;
            
        }
        catch (System.Exception error)
        {
            return error;
        }
    }
}

测试端点代码片段

[HttpPost]
[Route("api/objectCreation/test1")]
public async Task<dynamic> TestOne()
{
    try
    {
        projectviewerContext db = new projectviewerContext();
        ObjectBuilder objectBuilder = new ObjectBuilder(new GuidObjectBuilder(db), db);
        await objectBuilder.CreateOrUpdateObject("Project 1", "VV00011", "Gate Valve", "XXCCBBVVNNDDFFHH", "3D_Model.nwd");
        await objectBuilder.CreateOrUpdateObject("Project 1", "VV00012", "Gate Valve", "XXFFGGHHIILLMMNN", "3D_Model.nwd");
        await objectBuilder.CreateOrUpdateObject("Project 1", "VV00014", "Gate Valve", "123456789", "PID_drawing.nwd");
        return "bang";
    }
    catch (System.Exception error)
    {
        return error.Message;
    }
}

问题原因及解决办法

核心原因

问题大概率出在GuidObjectBuilder内部:你将同一个dbContext实例传给了ObjectBuilder和GuidObjectBuilder,如果GuidObjectBuilder的CreateOrUpdateUponModelOpen方法里存在释放dbContext的逻辑(比如用using包裹传入的dbContext、手动调用db.Dispose()),就会导致后续调用时ObjectBuilder持有的dbContext已被销毁。

另外,手动实例化dbContext的方式不符合ASP.NET Core的生命周期管理规范,也容易引发此类问题。

解决步骤

  1. 检查并修复GuidObjectBuilder的实现
    打开GuidObjectBuilder代码,确认CreateOrUpdateUponModelOpen方法中是否存在释放dbContext的逻辑:

    • 若有用using(var db = ...)包裹传入的dbContext,直接删除该结构
    • 若有调用db.Dispose(),立即移除该代码
      dbContext的生命周期应由外部(如依赖注入容器)统一管理,内部方法不应私自释放实例。
  2. 改用依赖注入管理DbContext生命周期(推荐)
    放弃手动new dbContext,通过ASP.NET Core依赖注入容器统一管理对象生命周期:

    • 在Program.cs中注册DbContext:
      builder.Services.AddDbContext<projectviewerContext>(options =>
          options.UseSqlServer(builder.Configuration.GetConnectionString("YourConnectionString")));
      
    • 注册GuidObjectBuilder和ObjectBuilder为Scoped服务(与DbContext生命周期一致):
      builder.Services.AddScoped<GuidObjectBuilder>();
      builder.Services.AddScoped<ObjectBuilder>();
      
    • 修改控制器,通过构造函数注入ObjectBuilder:
      private readonly ObjectBuilder _objectBuilder;
      
      public YourController(ObjectBuilder objectBuilder)
      {
          _objectBuilder = objectBuilder;
      }
      
      [HttpPost]
      [Route("api/objectCreation/test1")]
      public async Task<dynamic> TestOne()
      {
          try
          {
              await _objectBuilder.CreateOrUpdateObject("Project 1", "VV00011", "Gate Valve", "XXCCBBVVNNDDFFHH", "3D_Model.nwd");
              await _objectBuilder.CreateOrUpdateObject("Project 1", "VV00012", "Gate Valve", "XXFFGGHHIILLMMNN", "3D_Model.nwd");
              await _objectBuilder.CreateOrUpdateObject("Project 1", "VV00014", "Gate Valve", "123456789", "PID_drawing.nwd");
              return "bang";
          }
          catch (System.Exception error)
          {
              return error.Message;
          }
      }
      

    依赖注入容器会自动确保在整个请求周期内,dbContext实例不会被提前释放。

  3. 临时应急方案(不推荐,仅用于快速验证)
    若暂时无法修改依赖注入逻辑,可在测试端点中用using包裹dbContext实例,确保所有调用完成后才回收:

    [HttpPost]
    [Route("api/objectCreation/test1")]
    public async Task<dynamic> TestOne()
    {
        try
        {
            using(var db = new projectviewerContext())
            {
                ObjectBuilder objectBuilder = new ObjectBuilder(new GuidObjectBuilder(db), db);
                await objectBuilder.CreateOrUpdateObject("Project 1", "VV00011", "Gate Valve", "XXCCBBVVNNDDFFHH", "3D_Model.nwd");
                await objectBuilder.CreateOrUpdateObject("Project 1", "VV00012", "Gate Valve", "XXFFGGHHIILLMMNN", "3D_Model.nwd");
                await objectBuilder.CreateOrUpdateObject("Project 1", "VV00014", "Gate Valve", "123456789", "PID_drawing.nwd");
            }
            return "bang";
        }
        catch (System.Exception error)
        {
            return error.Message;
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 07:06:21