【发布时间】:2018-10-17 12:40:36
【问题描述】:
我有一个 web api 2 控制器,客户端向控制器请求某种 html 生成(包括图像、文件等)。由于这个过程需要一些时间,我不希望用户等待,我在控制器中遵循了以下方法:
...Controller(){
Task.Run(() =>
{
//calling heavy duty method to download files where Task.WaitAll() resides
DownloadAndRename()
});
}
DownloadAndRename(){
//created some child task here and run them in task.waitall()
//Task.WaitAll() here
}
我为每个文件创建了下载、重命名和其他过程的任务。然后在 Task.WaitAll() 中执行它们。
当我在本地运行应用程序时,一切正常。但是当我部署到我的测试服务器时,它抛出了以下异常:
Message: System.Threading.ThreadAbortException: Thread was being aborted.
附:在我的电脑中,我只有一个应用程序在应用程序池中运行,而在我的测试服务器中,该特定池中有 8 个。
如何克服异常?
更新 1:我尝试删除 task.WaitAll 并在不使用 Task 的情况下执行实施。不过,我得到线程中止错误,我认为 Task.Run() 以某种方式超时。
【问题讨论】:
-
您可以查看其他选项,例如 Hangfire。它旨在在 asp.net framework / asp.net core 中执行长时间运行的进程。
-
如果你想异步运行DownloadAndRename(),你可以把Task.Run()返回的Task传给Task.WaitAll()。 Task.WaitAll() 需要在 Controller() 范围内调用。但是请注意,Task.WaitAll() 将阻塞调用线程。是否可以使 Controller 方法异步并等待 DownloadAndRename() 代替?这将确保调用线程不会被阻塞。
-
@JamieButterworth,我已尝试删除 task.WaitAll,并在不使用 Task 的情况下执行实施。我仍然收到线程中止错误,我认为 Task.Run() 以某种方式超时。
-
问题是,asp.net 并没有“意识到”你正在处理的任务以及它围绕回收等的一些机制,只是试图保护 requests以及与之相关的事物。看起来这确实会更好地放置在一个单独的可执行文件中,例如 Windows 服务,然后 asp.net 应用程序通过某种形式的 IPC 与之交互。
-
这段代码保证了 ThreadAbortException。
Task.Run不等待就开始了一项任务,然后就忘记了它。Task.WaitAll()确保当 ASP.NET 在请求结束或回收时终止线程时,此任务仍然存在。有 LOT 的文章解释了如何在 ASP.NET 或 ASP.NET Core 中启动长时间运行的作业。你的目标是哪一个?
标签: c# asynchronous asp.net-web-api2