我有一个 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
写的行,但是当我像常规方法一样调用异步方法时,我只看到 “Before delay inside async” ,如果我用 Task.Run() 调用它,它会看到来自异步方法的两行。
问题 1: 谁能解释一下这种行为,为什么异步方法没有完全执行? 这是否与 Stephen Cleary 所说的有关:如果您出于任何原因丢失了 AppDomain,那么正在进行的工作也会丢失。
我阅读了这些文章,但无法弄清楚为什么会这样:
- How to call asynchronous method from synchronous method in C#?
- Fire and forget async method in asp.net mvc
- C# async/await with/without awaiting (fire and forget)
- https://blog.stephencleary.com/2012/12/returning-early-from-aspnet-requests.html根据大多数文章,不推荐我尝试做的事情(除其他外,异步方法的异常会被吞没)但在我的情况下,我已经有了生成响应所需的信息以及在异步方法根本不关心客户端...
上下文:我想要实现的是,在创建 X 资源
(将其保存在数据库中)的现有 API 路由上,创建 X 资源后,我想异步调用一个方法,该方法将使用来自该 X 资源的一些信息创建一个 json 文件并将其保存在文件系统中。但是即使文件写入失败,我想向客户端返回一个成功的响应(因为他的请求是实际保存 X Resource
- 成功了)他不关心创建外部XYZ 文件系统中的文件。
问题 2:考虑到 CreateResource 路由中链接的所有现有方法都是同步的,您认为实现上述目标的最佳实践是什么?
最佳答案
Question1: Can someone explain this behavior, why doesn't the async method execute fully? Does it have something to do with what Stephen Cleary says: If you lose your AppDomain for any reason, that in-progress work is lost.
没有。在这种情况下,AppDomain 仍然存在。在 ASP.NET(pre-Core)中,有一个 ASP.NET SynchronizationContext
表示请求。 await
by default captures the current context and uses that to resume executing its async
method .
因此,当 await
完成时,它会尝试在该请求的 SynchronizationContext
上恢复执行。但是,该请求已经完成,因此在该上下文中恢复没有意义。产生的行为是未定义的。
Question2: What would you say is the best practice to achieve what I described above, considering all the existing methods chained in the CreateResource route are sync?
如果您确定要提前返回,那么您应该有一个创建文件的后台服务句柄,而不是 ASP.NET 服务。由于您已经有一个数据库,您可以使用发件箱模式,将消息放在“发件箱”表中,作为与资源创建相同的事务的一部分。然后一个单独的后台服务读取“发件箱”表并写入 JSON 文件。
关于c# - 从同步方法调用异步方法是 ASP .NET web api - 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64611090/