【转】2.3async中必须始终返回Task(@Ron.liang)

Asp.Net Core 轻松学-经常使用异步的你,可能需要看看这个文章

目录

  • 前言
  • 1. 异常的发生来得太突然
  • 2. 问题所在
  • 3. 问题的解决方案

 

前言

事情的起因是由于一段简单的数据库连接代码引起,这段代码从语法上看,是没有任何问题;但是就是莫名其妙的报错了,这段代码极其简单,就是打开数据库连接,读取一条记录,然后立即更新到数据库中。但是,惨痛的事实证明,老司机也是会翻车的。

1. 异常的发生来得太突然

1.1 引起不舒适的代码片段

        [HttpPut]public async void Put([FromBody] TopicViewModel model){var topic = this.context.Topics.Where(f => f.Id == model.Id).FirstOrDefault();topic.Content = model.Content;this.context.Update(topic);var affrows = await this.context.SaveChangesAsync();}

这是一段不太标准的异步接口,可能你也这么写过, 从结构和语法上看,这段代码没有任何问题,而且正常情况下,它还能执行成功

1.2 报错信息

从报错信息中可以看出,数据库上下文对象被销毁了,是在什么时候销毁的呢,通过跟踪程序,了解到,是在 this.context.Update(topic); ,调用 Update 后执行了 DbContext.Dispose(),为了证明这点,我们重写 DbContext.Dispose() 方法,并简单的输出一句话

1.3 重写 DbContext.Dispose()

    public class ForumContext : DbContext{public ForumContext(DbContextOptions<ForumContext> options) : base(options){}public DbSet<Topic> Topics { get; set; }public DbSet<Post> Posts { get; set; }public override void Dispose(){base.Dispose();Console.WriteLine("Dispose");}}

1.4 再次执行程序,查看结果

通过输出结果红色方框处可以看到,确实是在执行了 Update 以后执行了 Dispose 方法,关于这点,如果我们使用了同步方法,先 Update 再 SaveChanges ,这是没有任何问题的,理论上说,EFCore 中启用了 AutoDetectChangesEnabled,我们在上面的代码中其实无需调用 Update,直接 SaveChangesAsync 即可,也不会抛出异常,同理,如果是在同步方法中,先执行 Update 再 SaveChanges ,也是没有任何问题的

1.5 同步 SaveChanges

        [HttpPut]public void Put([FromBody] TopicViewModel model){var topic = this.context.Topics.Where(f => f.Id == model.Id).FirstOrDefault();topic.Content = model.Content;this.context.Update(topic);Console.WriteLine("Updated");var affrows = this.context.SaveChanges();Console.WriteLine("affrows:{0}", affrows);}
  • 输出结果

从输出结果可知,先执行了 Update,然后执行了 SaveChanges 输出 affrows,最后执行了 Dispose 方法

2. 问题所在

那到底是什么问题引起了程序执行的不确定性呢,答案就是 async/await,我们先来尝试改进一下最初的代码

2.1 改进后的代码

        [HttpPut]public async Task Put([FromBody] TopicViewModel model){var topic = this.context.Topics.Where(f => f.Id == model.Id).FirstOrDefault();topic.Content = model.Content;this.context.Update(topic);Console.WriteLine("Updated");var affrows = await this.context.SaveChangesAsync();Console.WriteLine("affrows:{0}", affrows);}

细心的你已经发现,这段代码和 1.1 之中的没有太多的不同,无非是增加了一些跟踪信息,其中,最关键的是:增加了返回值为:Task ,替换了 void

2.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437247.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php隐藏webshell_PHP 安全的十个必备技巧

在这篇文章中&#xff0c;我将尝试为你提供一些可以提高 PHP 应用程序安全性的具体步骤。我关注的是 PHP 配置本身&#xff0c;所以我们不会讨论 SQL 注入、HTTPS 或其他与 PHP 无关的问题。我将使用我的 docker-entrypoint.sh 脚本中的 bash 行来说明示例&#xff0c;但当然你…

aop实现原理_Java:由浅入深揭开 AOP 实现原理

点击上方“Java专栏”&#xff0c;选择“置顶或者星标”第一时间阅读精彩文章&#xff01;1、☞ 程序员进阶必备资源免费送「21种技术方向&#xff01;」 点击查看☜2、☞ 《Java面试手册》.PDF 点击查看作者&#xff1a;马佩juejin.im/post/5bf4fc84f265da611b57f906概述&a…

【转】C#进阶系列——WebApi 接口参数不再困惑:传参详解

阅读目录 一、get请求 1、基础类型参数2、实体作为参数3、数组作为参数4、“怪异”的get请求二、post请求 1、基础类型参数2、实体作为参数3、数组作为参数4、后台发送请求参数的传递三、put请求 1、基础类型参数2、实体作为参数3、数组作为参数四、delete请求五、总结正文 前…

【转】01Teams的前世今生

说到Teams&#xff0c;这到底是一个什么产品&#xff1f;有人说它是团队协作工具&#xff0c;有人说它是云视频系统&#xff0c;有人说它是Hub&#xff0c;还有人说它是微软有史以来发展最快的一个产品&#xff0c;还有人说它完全是一个高效办公神器。其实都是对的。 Teams集成…

oracle insert 当前时间_Oracle知识点总结

目录1、Oracle的安装与下载2、基础查询3、条件查询 1)对比运算符 2)逻辑运算符 3)模糊查询 4)排序4、函数 1)数值函数 2)字符函数 3)时间日期函数 4)转换函数 5)通用函数5、聚合函数6、分组查询在学习Oracle之前&#xff0c;需要先有一定的数据库基…

【转】C#各类控件的输入输出(思维导图、知识点分析、案例解析)

第六周学习笔记—C#各类控件的输入输出 1.思维导图 知识点汇总&#xff1a; 着重介绍几个常用控件&#xff1a; 数据显示控件 DataGridView控件 列设置 a)、列的宽度铺满这个控件 设置如下&#xff1a;把AutoSizeColumnsModeFill;//可以在属性窗口中设置 b)、列名居中 代…

sqlserver连接字符串_10分钟使用EF Core连接MSSQL数据库

(给DotNet加星标&#xff0c;提升.Net技能)转自&#xff1a;Ron.liangcnblogs.com/viter/p/10243577.html前言在 .NET Core 2.2中Microsoft.AspNetCore.App 默认内置了EntityFramework Core 包&#xff0c;所以在使用过程中&#xff0c;我们无需再从NuGet仓库单独应用 EFCore 包…

【转】ADO.Net之SqlConnection、 Sqlcommand的应用学习心得(思维导图,知识解析,案例分析)

ADO.Net之SqlConnection、 Sqlcommand的应用 一、思维导图&#xff1a; ADO.NET与SQL连接&#xff1a; 二、知识点介绍&#xff1a; SqlConnection和Sqlcommand都是组成数据提供程序的类。 SqlConnection使用它来建立和数据库的连接&#xff0c;Sqlcommand使用它执行SQL命令…

professional中文_Microsoft office 2007 简体中文版

点击蓝字 关注小白软件名称&#xff1a;Microsoft office 2007软件语言&#xff1a;简体中文软件大小&#xff1a;0.67GB安装环境&#xff1a;Win10/8/7下载链接&#xff1a;https://pan.baidu.com/s/1DybozQ-rn-t2s2EC7FrvFw 提取码&#xff1a;zoa0安装步骤1、解压安装包&…

【转】设计模式 ( 十七) 状态模式State(对象行为型)

设计模式 ( 十七) 状态模式State&#xff08;对象行为型&#xff09; 1.概述 在软件开发过程中&#xff0c;应用程序可能会根据不同的情况作出不同的处理。最直接的解决方案是将这些所有可能发生的情况全都考虑到。然后使用if... ellse语句来做状态判断来进行不同情况的处理。…

【OSG学习】准备开发调试环境

环境 本人当前使用的环境是VS2013 Ultimate Update5 WIN10。 OSG编译安装 下载编译OSG源码不要克隆github上的源码&#xff0c;而是下载稳定版本的OSG源码进行编译。因为github上的源码处于开发阶段&#xff0c;我们应该优先选择稳定版本&#xff0c;我使用的是OpenSceneGr…

【Qt开发经验】Qt信号槽连接不成功问题原因汇总

以下几种情况会导致信号槽连接不成功&#xff0c;下面分别描述。 1. 拥有信号槽的类&#xff0c;必须继承QObject&#xff0c;声明Q_OBJECT宏。 Qt帮助手册里搜索 “Signals & Slots”&#xff0c;可以看到以下说明&#xff1a; 想要使用信号槽&#xff0c;必须继承QOb…

【转】.Net中的异步编程总结

一直以来很想梳理下我在开发过程中使用异步编程的心得和体会&#xff0c;但是由于我是APM异步编程模式的死忠&#xff0c;当TAP模式和TPL模式出现的时候我并未真正的去接纳这两种模式&#xff0c;所以导致我一直没有花太多心思去整理这两部分异步编程模型。今天在CodeProject上…

学习swing鼠标点击事件心得体会_西门子COMOS软件开发定制学习8-查询列表间的数据交互...

​本篇在西门子COMOS软件开发定制学习6-管理界面定制基础上定制&#xff0c;简单介绍两个查询列表之间的数据交互。实现效果&#xff1a;在左侧列表中选择某一设备&#xff0c;右侧列表自动根据所选设备&#xff0c;显示该设备相关的设计图纸(如PID图纸或电气图纸等)&#xff1…

【转】异步编程:.NET 4.5 基于任务的异步编程模型(TAP)

最近我为大家陆续介绍了“IAsyncResult异步编程模型 (APM)”和“基于事件的异步编程模式(EAP)”两种异步编程模型。在.NET4.0 中Microsoft又为我们引入了新的异步编程模型“基于任务的异步编程模型(TAP)”&#xff0c;并且推荐我们在开发新的多线程应用程序中首选TAP&#xff0…

python实验题_python实验二

安徽工程大学 Python 程序设计 实验报告 班级 物流191 姓名 王凡 学号 3190505102 成绩____________ 日期20200322 指导教师 修宇 【实验名称】 实验二 顺序结构程序设计 【思考题】 &#xff08;注意不要漏答&#xff09; 1、影响题1和题3计算准确性的因素有哪些&#xff1f;如…

解决:VS中进行Qt开发,编译时报错:打不开QWidgets.h等文件的问题

1. 先检查是否通过Qt VS Tools添加了Qt路径和配置了正确的Qt版本&#xff0c;这一步基本上都没问题。 2. 再检查此项目是否配置了正确的Qt版本&#xff0c;右键项目&#xff0c;选择Qt Project Settings&#xff0c;选择你需要的Qt版本即可&#xff0c;不可以为空。 3. 完成上面…

【转】1:C#的三种异步的详细介绍及实现

一、介绍异步的前世今生&#xff1a; 异步编程模型 (APM&#xff0c;Asynchronous Programming Model) 模式&#xff08;也称 IAsyncResult 模式&#xff09;&#xff0c;在此模式中异步操作需要 Begin 和 End 方法&#xff08;比如用于异步写入操作的 BeginWrite 和 EndWrite…

elasticsearch date_Elasticsearch在日志分析领域应用和运维实践

主要讲述了&#xff1a;基于ELK Kafka 的日志分析系统Elasticsearch 优化经验Elasticsearch 运维实践ElasticSearch介绍分布式实时分析搜索引擎&#xff0c;优点包括&#xff1a;查询近实时内存消耗小&#xff0c;搜索速度快可扩展性强高可用数据结构FST(Finite State Transdu…

【转】2:C#TPL探秘

理论&#xff1a; 1、 只要方法是 Task类型的返回值&#xff0c;都可以用 await 来等待调用获取返回值。 2、 如果一个返回 Task类型的方法被标记了 async&#xff0c;那么只要方法内部直接 return T 这个 类型的实例就可以。 3、 一个返回 Task类型的方法没有被标记了 asyn…