首页 > 解决方案 > 从同步方法调用异步方法是 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,那么正在进行的工作就会丢失。

我阅读了这些文章,但无法弄清楚为什么会这样:

上下文:我想要实现的是,在创建一个X Resource(将其保存在数据库中)的现有 API 路由上,在创建 X 资源后,我想异步调用一个方法,该方法将创建一个包含一些信息的 json 文件从该 X 资源中提取并将其保存在文件系统中。但是即使文件写入失败,我也想向客户端返回一个成功的响应(因为他的请求实际上是保存X Resource成功的 -)他并不关心在 XYZ 文件系统中创建外部文件。

问题 2:考虑到 CreateResource 路由中链接的所有现有方法都是同步的,您认为实现上述目标的最佳实践是什么?

标签: c#asp.net.netasynchronousasp.net-web-api2

解决方案


问题1:有人可以解释这种行为,为什么异步方法没有完全执行?这是否与 Stephen Cleary 所说的有关:如果您因任何原因丢失了 AppDomain,那么正在进行的工作就会丢失。

不。在这种情况下,AppDomain 仍然存在。在 ASP.NET(pre-Core)中,有一个SynchronizationContext代表请求的 ASP.NET。await默认情况下捕获当前上下文并使用它来恢复执行其async方法

因此,当await完成时,它会尝试继续执行SynchronizationContext该请求。但是,该请求已完成,因此在该上下文中恢复没有意义。产生的行为是未定义的。

问题2:考虑到在 CreateResource 路由中链接的所有现有方法都是同步的,您认为实现上述目标的最佳实践是什么?

如果您确定要提前返回,那么您应该有一个创建文件的后台服务句柄,而不是 ASP.NET 服务。由于您已经有一个数据库,您可以使用发件箱模式,将消息放在“发件箱”表中,作为与资源创建相同事务的一部分。然后一个单独的后台服务读取“发件箱”表并写入 JSON 文件。


推荐阅读