c# - 从同步方法调用异步方法是 ASP .NET web api - 问题
问题描述
我有一个 ASP .NET web api 2 应用程序,我试图从同步方法调用 asnyc 方法,同时我遇到了一些问题。如果我只是将该方法作为常规方法调用,则延迟后的主体不会被执行,如果我用 Task.Run() 调用它,它将被执行
public void CallingMethod(MethodExecutionArgs args)
{
//do something with the args
System.Diagnostics.Debug.WriteLine("BEFORE ");
WriteFileToDiskAsync(args); // If I run only this, I never see "WriteFile() - AFTER delay" in the output
Task.Run(async () => await WriteFileToDiskAsync(args)); // this executes the entire async method
System.Diagnostics.Debug.WriteLine($"Finally written from sync method");
}
private async Task<bool> WriteFileToDiskAsync(dynamic file)
{
System.Diagnostics.Debug.WriteLine("Before delay inside async");
await Task.Delay(3000);
System.Diagnostics.Debug.WriteLine("WriteFile() - AFTER delay");
}
结果:我总是看到从 写的行CallingMethod
,但是当我像常规方法一样调用异步方法时,我只看到“异步内部延迟之前”,如果我用 Task.Run() 调用它,它会看到异步中的两行方法。
问题1:有人可以解释这种行为,为什么异步方法没有完全执行?这是否与 Stephen Cleary 所说的有关:如果您因任何原因丢失了 AppDomain,那么正在进行的工作就会丢失。
我阅读了这些文章,但无法弄清楚为什么会这样:
- 如何从 C# 中的同步方法调用异步方法?
- 在 asp.net mvc 中触发并忘记异步方法
- C# async/await 有/无等待(即发即弃)
- https://blog.stephencleary.com/2012/12/returning-early-from-aspnet-requests.html 根据大多数文章我不推荐我正在尝试做的事情(除其他外,异步方法的例外情况会被吞下)但在我的情况下,我已经有了生成响应所需的信息,并且在 Async 方法中所做的事情根本不关心客户端......
上下文:我想要实现的是,在创建一个X Resource
(将其保存在数据库中)的现有 API 路由上,在创建 X 资源后,我想异步调用一个方法,该方法将创建一个包含一些信息的 json 文件从该 X 资源中提取并将其保存在文件系统中。但是即使文件写入失败,我也想向客户端返回一个成功的响应(因为他的请求实际上是保存X Resource
成功的 -)他并不关心在 XYZ 文件系统中创建外部文件。
问题 2:考虑到 CreateResource 路由中链接的所有现有方法都是同步的,您认为实现上述目标的最佳实践是什么?
解决方案
问题1:有人可以解释这种行为,为什么异步方法没有完全执行?这是否与 Stephen Cleary 所说的有关:如果您因任何原因丢失了 AppDomain,那么正在进行的工作就会丢失。
不。在这种情况下,AppDomain 仍然存在。在 ASP.NET(pre-Core)中,有一个SynchronizationContext
代表请求的 ASP.NET。await
默认情况下捕获当前上下文并使用它来恢复执行其async
方法。
因此,当await
完成时,它会尝试继续执行SynchronizationContext
该请求。但是,该请求已完成,因此在该上下文中恢复没有意义。产生的行为是未定义的。
问题2:考虑到在 CreateResource 路由中链接的所有现有方法都是同步的,您认为实现上述目标的最佳实践是什么?
如果您确定要提前返回,那么您应该有一个创建文件的后台服务句柄,而不是 ASP.NET 服务。由于您已经有一个数据库,您可以使用发件箱模式,将消息放在“发件箱”表中,作为与资源创建相同事务的一部分。然后一个单独的后台服务读取“发件箱”表并写入 JSON 文件。
推荐阅读
- memory-management - Julia 1.1 与 JLD HDF5 包和 Windows 中的内存释放
- php - PHP 将用户文本回显到聊天框 div 导致未定义索引错误(我的问题与 session_start(); 位置无关)
- c++ - 没有匹配的函数调用错误。将字符串推入向量
- javascript - 使用 Nodejs 和 ffmpeg 将 GIF 转换为 MP4,并将缓冲区作为输入
- python-3.x - python aiohttp响应时间慢
- java - 登录参数未使用 Volley 通过 REST 发布
- docker - 如何正确关闭这些 k8 容器?
- python - 在 QML 中显示 pandas 数据框
- python - 正则表达式用带有空白的http替换整个字符串
- java - 如何按递减顺序循环字符串?