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

.NET Core Web API中DbContext触发ObjectDisposedException异常求助

问题:.NET Core Web API中使用泛型仓储模式触发ObjectDisposedException异常

场景说明

我是C#和.NET Core的新手,正在基于.NET Core Web API 3.1和EntityFramework开发项目,采用泛型仓储模式。

1. IRepository接口定义

public interface IRepository<T> where T:class
{
    void InsertObject(T obj);
    void DeleteObject(int objId);
    void UpdateObject(T obj);
    T GetObjectById(int obj);
    IEnumerable<T> GetObjectList();
}

2. Repository泛型实现类

public class Repository<T> : IRepository<T> where T : class
{
    private readonly ClothingContext dbContext;

    public Repository(ClothingContext clothing)
    {
        dbContext = clothing;
    }
    // 多余方法,与接口定义不符且逻辑重复
    public void Insert(int objId){
        var obj = dbContext.Set<T>().Find(objId);
        dbContext.Set<T>().Remove(obj);
        dbContext.SaveChanges();
    }

    public T GetObjectById(int obj)
    {
        return dbContext.Set<T>().Find(obj);
    }

    public IEnumerable<T> GetObjectList()
    {
        var originalObjects = dbContext.Set<T>().ToList();
        return originalObjects;
    }

    public void InsertObject(T obj)
    {
        dbContext.Set<T>().Add(obj);
        dbContext.SaveChanges();
    }

    public void UpdateObject(T obj)
    {
        dbContext.Entry(obj).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
    }

    public void DeleteObject(int objId)
    {
        var obj = dbContext.Set<T>().Find(objId);
        dbContext.Set<T>().Remove(obj);
        dbContext.SaveChanges();
    }
}

3. ProductRepository特定仓储类

public class ProductRepository : Repository<Product>
{
    private static ProductRepository productRepository;
    public ProductRepository(ClothingContext clothingContext) : base(clothingContext)
    {
    }

    public static ProductRepository GetInstance(ClothingContext clothing)
    {
        if(productRepository == null)
        {
            productRepository = new ProductRepository(clothing);
        }
        return productRepository;
    }
}

该类未来会添加自有方法,目前仅实现了单例模式。

4. Startup.cs的ConfigureServices配置

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ClothingContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ClothingApp11270")));
    services.AddControllers();
    services.AddTransient<IRepository<Product>, ProductRepository>();
}

5. ProductController控制器代码

[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
    private readonly ProductRepository productRepository;

    public ProductController(ClothingContext clothingContext)
    {
        productRepository = ProductRepository.GetInstance(clothingContext);
    }
    // GET: api/<ProductController>
    [HttpGet]
    public IActionResult Get()
    {
        return new OkObjectResult(productRepository.GetObjectList());
    }

    // GET api/<ProductController>/5
    [HttpGet("{id}" ,Name ="GetProductById")]
    public IActionResult Get(int id)
    {
        return new OkObjectResult(productRepository.GetObjectById(id));
    }

    // POST api/<ProductController>/a
    [HttpPost]
    public IActionResult Post([FromBody] Product product)
    {
        using(var scope = new TransactionScope())
        {
            productRepository.InsertObject(product);
            scope.Complete();
            return CreatedAtAction(nameof(Get), new { ID = product.Id }, product);
        }
    }

    // PUT api/<ProductController>/5
    [HttpPut]
    public IActionResult Put([FromBody] Product product)
    {
        if(product != null)
        {
            using (var scope = new TransactionScope())
            {
                productRepository.UpdateObject(product);
                scope.Complete();
                return new OkResult();
            }
        }
        return new NoContentResult();
    }

    // DELETE api/<ProductController>/5
    [HttpDelete("{id}")]
    public IActionResult Delete(int id)
    {
        productRepository.DeleteObject(id);
        return new OkResult();
    }
}

问题现象

每当执行POST或GET请求时,都会触发ObjectDisposedException异常。


解决方案

核心问题原因

  1. 单例仓储与DbContext生命周期冲突:
    • 默认AddDbContext注册的ClothingContext是Scoped生命周期(每个请求创建一个实例,请求结束后自动释放)。
    • 手动实现的ProductRepository单例会持有第一次请求的DbContext实例,请求结束后该DbContext被框架释放,后续请求使用单例仓储时就会访问已释放的对象,抛出异常。
  2. 控制器依赖注入错误:
    已在Startup中注册仓储的DI映射,但控制器绕过DI容器,直接通过GetInstance创建单例,完全脱离了生命周期管理。

修复步骤

步骤1:移除ProductRepository的单例实现

依赖DI容器管理实例,不需要手动实现单例:

public class ProductRepository : Repository<Product>
{
    public ProductRepository(ClothingContext clothingContext) : base(clothingContext)
    {
    }
    // 删除GetInstance静态方法和静态实例字段
}

步骤2:修改控制器,通过依赖注入获取仓储

直接注入注册的IRepository<Product>,而非ClothingContext:

[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
    private readonly IRepository<Product> _productRepository;

    public ProductController(IRepository<Product> productRepository)
    {
        _productRepository = productRepository;
    }

    [HttpGet]
    public IActionResult Get()
    {
        return Ok(_productRepository.GetObjectList());
    }

    // 其余Action方法保持逻辑不变,仅替换为使用_productRepository
}

步骤3:修正Repository类的问题

  • 删除多余的Insert(int objId)方法,避免与接口定义冲突;
  • 给UpdateObject补充SaveChanges(),确保修改持久化:
public void UpdateObject(T obj)
{
    dbContext.Entry(obj).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
    dbContext.SaveChanges(); // 添加此行
}

步骤4:调整仓储生命周期(可选)

若不需要每次请求创建新仓储,可将注册改为Scoped(与DbContext生命周期一致):

// Startup.cs的ConfigureServices中
services.AddScoped<IRepository<Product>, ProductRepository>();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 06:44:57