简体   繁体   English

从同步方法调用异步方法是 ASP .NET web api - 问题

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM