[英]Calling async method from sync method is ASP .NET web api - issue
I have a ASP .NET web api 2 application, and I'm trying to call asnyc method from sync method and meanwhile I encountered some issues.我有一个 ASP .NET web api 2 应用程序,我试图从同步方法调用 asnyc 方法,同时我遇到了一些问题。 If I just call the method as a regular method the body after delay doesn't get executed, if I call it with Task.Run() it gets executed如果我只是将该方法作为常规方法调用,则延迟后的主体不会被执行,如果我用 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");
}
Result: I always see the lines written from CallingMethod
, but when I call the async method like a regular method, I only see the "Before delay inside async" , If I call it with Task.Run() it see both lines from the async method.结果:我总是看到从CallingMethod
写的行,但是当我像常规方法一样调用异步方法时,我只看到“在异步内部延迟之前” ,如果我用 Task.Run() 调用它,它会看到来自异步方法。
Question1: Can someone explain this behavior, why doesn't the async method execute fully?问题 1:有人可以解释这种行为,为什么 async 方法没有完全执行? 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.这是否与 Stephen Cleary 所说的有关:如果您因任何原因丢失了 AppDomain,那么正在进行的工作就会丢失。
I read these articles but can't figure out why is this happening:我阅读了这些文章,但无法弄清楚为什么会发生这种情况:
Context: What I'm trying to achieve is, on a existing API route that creates a X Resource
(saves it in a database), after the X resource is created, I want to asynchronously call a method that will Create a json file with some information from that X Resource and save it in a filesystem.上下文:我想要实现的是,在创建X Resource
(将其保存在数据库中)的现有 API 路由上,在创建X Resource
后,我想异步调用一个方法,该方法将创建一个 json 文件来自该 X 资源的一些信息并将其保存在文件系统中。 But even if the writing of the file fails, I want to return a successful response to the client (because his request was to actually save the X Resource
- which succeeded) he doesn't care about Creating external file in XYZ filesystem.但即使文件写入失败,我也想向客户端返回一个成功的响应(因为他的请求是实际保存X Resource
- 成功了)他并不关心在 XYZ 文件系统中创建外部文件。
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?问题 2:考虑到 CreateResource 路由中链接的所有现有方法都是同步的,您认为实现上述目标的最佳实践是什么?
Question1: Can someone explain this behavior, why doesn't the async method execute fully?问题 1:有人可以解释这种行为,为什么 async 方法没有完全执行? 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.这是否与 Stephen Cleary 所说的有关:如果您因任何原因丢失了 AppDomain,那么正在进行的工作就会丢失。
No. The AppDomain is still there in this case.不。在这种情况下,AppDomain 仍然存在。 In ASP.NET (pre-Core), there is an ASP.NET SynchronizationContext
that represents the request.在 ASP.NET(pre-Core)中,有一个代表请求的 ASP.NET SynchronizationContext
。 await
by default captures the current context and uses that to resume executing its async
method . 默认情况下await
捕获当前上下文并使用它来恢复执行其async
方法。
So, when the await
completes, it attempts to resume executing on the SynchronizationContext
for that request.因此,当await
完成时,它会尝试继续在SynchronizationContext
上为该请求执行。 However, that request has been completed, and so it doesn't make sense to resume on that context.但是,该请求已完成,因此在该上下文中恢复没有意义。 The resulting behavior is undefined.由此产生的行为是未定义的。
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?问题 2:考虑到 CreateResource 路由中链接的所有现有方法都是同步的,您认为实现上述目标的最佳实践是什么?
If you are sure you want to return early, then you should have a background service handle creating the file, not the ASP.NET service.如果您确定要提前返回,那么您应该有一个后台服务句柄来创建文件,而不是 ASP.NET 服务。 Since you have a database already, you could use the Outbox Pattern, where you place messages in an "outbox" table as part of the same transaction as your resource creation.由于您已经拥有一个数据库,因此您可以使用发件箱模式,将消息放在“发件箱”表中,作为与您的资源创建相同的事务的一部分。 Then a separate background service reads the "outbox" table and writes the JSON file.然后一个单独的后台服务读取“发件箱”表并写入 JSON 文件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.