我试图向同事解释为什么async void
功能不好而异常不会被抓住,但事实证明我可能没理解他们。我们有一段看起来像这样的代码:
public ActionResult EmailCandidates(List<string> identityTokens, string subject, string content)
{
// generate list of recipients here
SendEmail(recipients, subject, content); //not awaited
return new AjaxResponse { // AjaxResponse is a wrapper around JSONResponse
IsSuccess = true,
Data = recipients.Select(r=>r.Name)
};
}
private async void SendEmail(List<EmailAddress> recipients, string subject, string content)
{
await Task.Delay(10000); // simulate async send email
throw new Exception(); // manually added
}
我期待的是什么,以及我试图解释的是,如果SendEmail
函数抛出异常,它将无法正常捕获,因为主函数EmailCandidates
已经返回给客户端。只有那不是发生的事情。上面的代码完全按照我期望的顺序执行:
EmailCandidates
SendEmail
被称为EmailCandidates
,并执行返回然后它变得有点奇怪:
EmailCandidates
已经返回那么为什么即使EmailCandidates
已经返回,也不会将响应发送给客户端。如何知道等待异步SendEmail
函数?
答案 0 :(得分:3)
ASP.NET提供了一个import IPython
import IPython.core.history as H
## spews a UserWarning about locate_profile() ... seems safe to ignore
HISTORY = H.HistoryAccessor()
def dedupe_history():
query = ("DELETE FROM history WHERE rowid NOT IN "
"(SELECT MAX(rowid) FROM history GROUP BY source)")
db = HISTORY.db
db.execute(query)
db.commit()
def set_pre_run_cell_event():
IPython.get_ipython().events.register("pre_run_cell", dedupe_history)
## dedupe history at start of new session - maybe that's sufficient, YMMV
dedupe_history()
## run dedupe history every time you run a command
set_pre_run_cell_event()
,它可以跟踪飞行中的异步操作数,并且在完成所有操作之前不会发送结果。请注意,ASP.NET Core中已删除此SynchronizationContext
。
但是,即使在ASP.NET上也不应该看到这种行为。对于调用SynchronizationContext
方法的同步方法,您应该看到async void
,其中包含“此时无法启动异步操作”的消息。在异步方法调用InvalidOperationException
方法(在处理程序返回之前未完成)的情况下,您应该看到async void
,其中包含异步操作时异步模块或处理程序已完成的消息还在等待。“
由于这些安全网都没有触发,我怀疑你的ASP.NET代码是使用旧版本的ASP.NET。这些安全网是在.NET 4.5中添加的,您不仅要将其作为构建目标,还要 必须add targetFramework
in your web.config
。
具有以下代码的新.NET 4.5.2 ASP.NET MVC应用程序会立即抛出InvalidOperationException
,如预期的那样:
InvalidOperationException
答案 1 :(得分:0)
您的应用程序运行正常,实际上是遵循MVC的默认行为。如果你明确地说明了异常,那么当请求来自应用程序所在的同一台机器(localhost)时,如果你想看看实际用户想要看到你需要更改的那个,那么就会出现这种错误(500)。 webconfig上的值默认情况下,它设置为RemoteOnly。
如果你去过FilterConfig。你会看到这行代码
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
尝试将值更改为“On”,您将看到您在该错误页面上结束,因为处理程序错误属性,它在操作上提供后处理逻辑,以及何时发现异常已从操作中转义它将显示错误视图而不是黄色死亡屏幕。默认情况下,视图位于View / Shared / Error.cshtml
中的应用程序中你的关闭选项
指定禁用自定义错误。这允许显示 详细错误。
供参考:https://msdn.microsoft.com/en-us/library/h0hfz6fc(v=vs.71).aspx
如果您只放置遥控器,那么如果您在本地机器中调试网站,则会继续看到错误,但如果您托管应用程序,则最终用户将看不到该错误。