我有一个异步操作,它应该在等待一些任务后向浏览器返回一条JSON消息。尽管ActionResult已经成功构建并执行(我使用的是我自己的JsonResult,所以我通过进入源代码来确认这一点),但浏览器仍然没有得到任何响应(Fiddler确认了)。
同时,如果我正在等待Task.Delay()
,并返回一条伪消息,它就会起作用。
奇怪的是,如果我在IIS Express运行我的网站时使用VS2013重建我的项目,浏览器会突然收到几分钟前应该发送的消息!我认为这是关闭网络服务器造成的,但我不知道这到底是怎么发生的。
我已经调试了一天,禁用了所有我认为可能相关的东西,但运气不佳。因此,任何关于这种奇怪行为的原因的帮助都是受欢迎的。谢谢,这是代码:
[HttpPost]
public async Task<JsonResult> Update(string token)
{
try
{
//This works
//await Task.Delay(TimeSpan.FromSeconds(1));
//return Json(new { error = "testing." });
//This won't work
var feedback = await ServerConnectionKeeper.UpdateStation(token);
return feedback.Success
? Json(new { redirect = Url.Action("Index", "Home") })
: Json(new { error = feedback.Error });
}
catch (Exception ex)
{
return Json(new { error = ex.Message });
}
}
原来我调用了一个async void
方法,它使一些奇怪的未知(我)事情发生了。以下是一些概念代码:
[HttpPost]
public async Task<JsonResult> Data()
{
await SomeTask();
return Json(new { message = "Testing" });
}
private async Task SomeTask()
{
FireAndForget();
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
}
private async void FireAndForget()
{
await Task.Delay(TimeSpan.FromSeconds(100)).ConfigureAwait(false);
}
对于上面的代码,我认为在请求后1秒就会得到响应。但事实并非如此,甚至不到100秒。在某些情况下,我会得到InvalidOperationException
,而在其他情况下,则一无所获。
如果我把async void
改成async Task
,不管是不是ConfigureAwait(false)
,一切都会起作用:
[HttpPost]
public async Task<JsonResult> Data()
{
await SomeTask();
return Json(new { message = "Testing 4" });
}
private async Task SomeTask()
{
FireAndForget();
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
}
private async Task FireAndForget()
{
await Task.Delay(TimeSpan.FromSeconds(100)).ConfigureAwait(false);
}
在我的生产代码中,当web服务器关闭时发送响应的原因是,我的FireAndForget()
方法有一个async
循环读取网络消息,并且在连接关闭之前从不返回,关闭web服务器会关闭连接。但我仍然觉得奇怪的是,我没有在那里拿到InvalidOperationException
。