ef core上下文对象在异步情况下被自动释放的问题。Cannot access a disposed object. A common cause of this error is disposing a context that was resolved
我们看看下面的代码:
这里为了节省效率,更新缓存的操作放到了异步中去执行,但是执行到Article findArticle = _articleDAL.GetAtricleById(id);这一步的时候,ef的上下文对象会被释放掉,调用查询等操作就会报错:Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance
我对这个原因的理解:
是依赖注入生命周期的问题,scope模式是同一个请求获取得到相同的实例(ef注入的默认方式是scope),然后我又使用task开了一个先线程形成异步,这样就造成请求执行完了对象就已经释放了,然后线程里边缺还去用到了ef的上下文对象,所以得到的就是为空的
对.net core注入模式的了解可以参考:http://www.tnblog.net/aojiancc2/article/details/167
对于默认模式我们在这里也可以看到
想到的解决方法:
方法一:先把需要的数据查询出来然后在使用异步
这样就不怕ef上下文对象被释放了,因为不需要用到了
方法二:我在想既然对象会被释放,那我在异步中重新去依赖注入容器获取一下不就行了
但是这样并不行,要么就是HttpContext对象被释放
那么就是ef上下文对象被释放:
即使你把重新获取的代码放到异步的外面,获取到的ef上下文对象依然是被释放的,因为scope模式是同一个请求获取得到相同的实例,请求完了这个上下文对象就会被释放
方法三:修改ef上下文注入的方式
变成Transient瞬时模式,每次从容器获取都能得到不同的对象
然而还是会被释放,因为我们_articleDAL还是在主线程被创建的,所以_articleDAL下面关联的ef上下文对象也是属于主线程的,主线程执行完了,ef上下文对象依然会被释放
方法四:修改生命周期和重新去依赖注入容器获取结合使用,也就是2,3方法结合一起使用
这样不就可以在异步方法所在线程中维护对象的生命周期么,只要异步所在的线程没有执行完,对象就不会被释放
然而并没有什么卵用还是不行,为什么和想像中的不一样呢。不用异步没有问题,先查询出来在异步更新缓存也没有问题。
但是在异步中去使用ef查询始终有问题呢,难道是因为HttpContext是在主线程中么,所以用它从容器中获取的对象其实还是受主线程的控制,
而且在异步方法中使用HttpContext去获取对象本身就是不科学的。
方法五:更新方法2中的获取依赖注入对象的方式
不去使用HttpContext的方式获取,因为HttpContext本身就属于请求那次的线程
我们使用静态类的方式去获取对象
果然这个问题确实是我们猜想的那样换种获取对象的方法就不会有问题了
net core手动获取依赖注入对象可以参考:
http://www.tnblog.net/aojiancc2/article/details/2980
算了我们绕了这么大一个圈圈其实还是第一种方法最简单,科学
tip:当然你还可以考虑使用单例模式或者AddDbContextPool方式注入,我这里就暂时不尝试了,先弄其他东西了