asp.net - 在 MVC Action 中启动和忘记异步任务

标签 asp.net asynchronous synchronous invalidoperationexception controller-action

我有一个标准的非异步操作,例如:

[HttpPost]
public JsonResult StartGeneratePdf(int id)
{
    PdfGenerator.Current.GenerateAsync(id);
    return Json(null);
}

我的想法是,我知道 PDF 生成可能需要很长时间,因此我只是启动任务并返回,而不关心异步操作的结果。

在默认的 ASP.Net MVC 4 应用程序中,这给了我一个很好的异常(exception):

System.InvalidOperationException: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>.

这与我的场景无关。调查一下,我可以将标志设置为 false 以防止出现此异常:

<appSettings>
    <!-- Allows throwaway async operations from MVC Controller actions -->
    <add key="aspnet:AllowAsyncDuringSyncStages" value="true" />
</appSettings>

https://stackoverflow.com/a/15230973/176877
http://msdn.microsoft.com/en-us/library/hh975440.aspx

但问题是,启动此异步操作并从同步 MVC Controller 操作中忘记它是否有任何危害?我能找到的所有内容都建议使 Controller 异步,但这不是我想要的 - 没有意义,因为它应该总是立即返回。

最佳答案

放松,正如 Microsoft 自己所说 ( http://msdn.microsoft.com/en-us/library/system.web.httpcontext.allowasyncduringsyncstages.aspx ):

This behavior is meant as a safety net to let you know early on if you're writing async code that doesn't fit expected patterns and might have negative side effects.

只需记住一些简单的规则:

  • 永远不要在(异步或非异步)空事件中等待(因为它们立即返回)。某些 WebForms 页面事件支持内部的简单等待 - 但 RegisterAsyncTask 仍然是高度首选的方法。

  • 不要等待 async void 方法(因为它们会立即返回)。

  • 不要在 GUI 或请求线程中同步等待(.Wait().Result().WaitAll(), WaitAny()) 上的异步方法上没有 .ConfigureAwait(false) on root wait 内部或其根 Task 未使用 .Run() 启动,或者没有显式指定 TaskScheduler.Default(因为 GUI 或请求将因此死锁)。

  • 使用 .ConfigureAwait(false)Task.Run 或为每个后台进程显式指定 TaskScheduler.Default,并在每个库方法都不需要需要在同步上下文上继续 - 将其视为“调用线程”,但要知道它不是一个(并且并不总是在同一个线程上),并且甚至可能不再存在(如果请求已经结束)。仅此一点就可以避免最常见的异步/等待错误,并且还可以提高性能。

微软只是假设你忘记等待你的任务......

更新:正如斯蒂芬在他的回答中明确指出的那样(不是双关语),在使用应用程序池时,所有形式的“即发即弃”都存在继承但隐藏的危险,而不仅仅是特定的危险只是异步/等待,但任务、线程池和所有其他此类方法也是如此 - 一旦请求结束,它们保证完成(应用程序池可能会由于多种原因随时回收) .

您可能关心或不关心这一点(如果它不像OP的特殊情况那样对业务至关重要),但您应该始终意识到这一点。

关于asp.net - 在 MVC Action 中启动和忘记异步任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16469094/

相关文章:

c# - 为什么我不能在套接字连接上发送两次数据?

java - 使用具有返回值的同步方法包装一系列异步调用

html - 加载并执行传统(同步)Google Analytics 跟踪代码片段作为第一个 DOM 元素

c# - 脚本不在代码后面工作

javascript - 如何在 Sharepoint 中调试 JavaScript?

c# - Webapi2-完成一项任务后从 Controller 操作返回,但继续进行进一步的异步处理

javascript - 等待函数输出不超过一定时间的最佳方法是什么?

javascript - 如何在javascript中处理xml字符串

asp.net - 无法更新 Gridview 中文本框的值 : Object reference not set to instance of an object

c# - 无法从动态生成的文件上传控件中保存文件