网站生成器,专业制作公众号公司,wordpress前端会员,手机制作视频的软件app哪个更好前言事情的起因是由于一段简单的数据库连接代码引起#xff0c;这段代码从语法上看#xff0c;是没有任何问题#xff1b;但是就是莫名其妙的报错了#xff0c;这段代码极其简单#xff0c;就是打开数据库连接#xff0c;读取一条记录#xff0c;然后立即更新到数据库中… 前言事情的起因是由于一段简单的数据库连接代码引起这段代码从语法上看是没有任何问题但是就是莫名其妙的报错了这段代码极其简单就是打开数据库连接读取一条记录然后立即更新到数据库中。但是惨痛的事实证明老司机也是会翻车的。1. 异常的发生来得太突然1.1 引起不舒适的代码片段这是一段不太标准的异步接口可能你也这么写过 从结构和语法上看这段代码没有任何问题而且正常情况下它还能执行成功1.2 报错信息从报错信息中可以看出数据库上下文对象被销毁了是在什么时候销毁的呢通过跟踪程序了解到是在 this.context.Update(topic); 调用 Update 后执行了 DbContext.Dispose()为了证明这点我们重写 DbContext.Dispose() 方法并简单的输出一句话1.3 重写 DbContext.Dispose()1.4 再次执行程序查看结果通过输出结果红色方框处可以看到确实是在执行了 Update 以后执行了 Dispose 方法关于这点如果我们使用了同步方法先 Update 再 SaveChanges 这是没有任何问题的理论上说EFCore 中启用了 AutoDetectChangesEnabled我们在上面的代码中其实无需调用 Update直接 SaveChangesAsync 即可也不会抛出异常同理如果是在同步方法中先执行 Update 再 SaveChanges 也是没有任何问题的1.5 同步 SaveChanges输出结果从输出结果可知先执行了 Update,然后执行了 SaveChanges 输出 affrows最后执行了 Dispose 方法2. 问题所在那到底是什么问题引起了程序执行的不确定性呢答案就是 async/await我们先来尝试改进一下最初的代码2.1 改进后的代码细心的你已经发现这段代码和 1.1 之中的没有太多的不同无非是增加了一些跟踪信息其中最关键的是增加了返回值为Task 替换了 void2.2 再次执行修正的程序输出结果和 1.5 中的同步方法完全相同至此问题解决3. 问题的解决方案3.1 问题分析为什么会发生这种问题呢原因就是因为使用了异步方法 async/await 时当没有值需要返回时使用了 void 造成的正确的做法是如果没有返回值则返回 Task如果有返回值则使用 Task 当一个异步方法内部没有返回 Task 的时候基于任务的异步模式TAP并不知道异步任务的状态当 this.context.Update 执行完成后发现挂载在内存中的连接已经没有使用就执行了回收实际上此时程序还没有执行完成但是 TAP 并不知道所以它不会去阻止这个回收的过程使用标记所以 async/await 应该成对出现并且应该始终返回 Task 或者 Task以确保 TAP 能够将上下文进行正确的挂载否则当异常发生时TAP 无非将异常信息挂载到相应的 Task 上亦无法跟踪其执行状态等信息3.2 解决方案请牢记下面的铁律3.2.1 在 EFCore 中应当始终发挥 AutoDetectChangesEnabled 的特性不要再更新实体的时候去调用 Update 方法3.2.2 使用 async/await 修饰方法时应该始终返回 Task 或者 Task适当的使用同步方法可避免异步踩坑演示代码下载https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/Ron.TaskThird原文地址:https://www.cnblogs.com/viter/p/10271212.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com