1 public class BaseRepositories<T> where T : class 2 { 3 private readonly RepositoryDbContext _context; 4 5 public BaseRepositories(RepositoryDbContext context) 6 { 7 _context = context; 8 } 9 10 /// <summary> 11 /// 添加 12 /// </summary> 13 /// <param name="entity"></param> 14 /// <returns></returns> 15 public async Task<bool> Add(T entity) 16 { 17 18 await _context.Set<T>().AddAsync(entity); 19 return await _context.SaveChangesAsync() > 0;//执行到这行会报错 20 /* 错误信息: 21 * 无法访问已释放的对象。导致此错误的一个常见原因是处理从依赖项注入解析的上下文, 22 * 然后在应用程序的其他地方尝试使用相同的上下文实例。如果对上下文调用Dispose(), 23 * 或将上下文包装到using语句中,则可能会发生这种情况。如果使用的是依赖项注入, 24 * 则应让依赖项注入容器处理上下文实例。\r\n对象名称:“RepositoryDbContext” 25 */ 26 } 27 }
1.通过分析原因是:
数据库上下文对象被销毁了,是在什么时候销毁的呢?通过跟踪程序 是在 _context.AddAsync(entity);
调用AddAsync后, 执行了DbContext.Dispose(),可以通过重写 DbContext.Dispose() 方法来输出执行顺序来证明。这里就不做演示了。
2.问题解决方案:三个方式
2.1通过使用同步方法_context.Add()和_context.SaveChanges()
这个方法比较简单,如果要实现异步,自定义一个异步方法将其包含就可以了。
2.2不用依赖注入的上下文, 而是临时生成上下文, 具体步骤如下:
此方法并非完全不使用依赖注入, 只是舍弃依赖注入上下文,而使用依赖注入的DbContextOptions<T>来构造临时上下文
1 public class BaseRepositories<T> where T : class 2 { 3 private readonly RepositoryDbContext _context; 4 5 // 1. 采用依赖注入获得DbContextOptions 6 private readonly DbContextOptions<RepositoryDbContext> _options; 7 public BaseRepositories(RepositoryDbContext context, DbContextOptions<RepositoryDbContext> options) 8 { 9 _options = options; 10 _context = context; 11 } 12 13 /// <summary> 14 /// 添加 15 /// </summary> 16 /// <param name="entity"></param> 17 /// <returns></returns> 18 public async Task<bool> Add(T entity) 19 { 20 // 2. 用optins生成临时上下文, 执行异步SaveChangesAsync() 21 using (var context = new RepositoryDbContext(_options)) 22 { 23 await context.Set<T>().AddAsync(entity); 24 return await context.SaveChangesAsync() > 0; 25 } 26 27 } 28 }
3.通过注册服务时使用单例模式:
在网上搜到相关的Dispose原因,是上下文的生命周期的问题。
services.AddDbContext<RepositoryDbContext>(options => options.UseSqlServer( Configuration.GetConnectionString("AppOptions")), ServiceLifetime.Singleton, ServiceLifetime.Singleton);