.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异常。
解决方案
核心问题原因
- 单例仓储与DbContext生命周期冲突:
- 默认
AddDbContext注册的ClothingContext是Scoped生命周期(每个请求创建一个实例,请求结束后自动释放)。 - 手动实现的
ProductRepository单例会持有第一次请求的DbContext实例,请求结束后该DbContext被框架释放,后续请求使用单例仓储时就会访问已释放的对象,抛出异常。
- 默认
- 控制器依赖注入错误:
已在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
相关产品推荐
相关产品推荐

