MVC函数返回但在发送结果

时间:2017-02-22 16:32:53

标签: c# asp.net-mvc asynchronous async-await

我试图向同事解释为什么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已经返回
  • 10秒后抛出异常
  • 异常被全局错误处理程序捕获,现在客户端收到500错误(不出所料)

那么为什么即使EmailCandidates已经返回,也不会将响应发送给客户端。如何知道等待异步SendEmail函数?

2 个答案:

答案 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

如果您只放置遥控器,那么如果您在本地机器中调试网站,则会继续看到错误,但如果您托管应用程序,则最终用户将看不到该错误。