【发布时间】:2017-04-18 17:40:03
【问题描述】:
在将现有同步方法转换为异步时,我不小心在其中一个方法上使用了“async void”,这导致了一些意外行为。
以下是我实际执行的更改的简化示例,
public IActionResult Index()
{
var vm = new ViewModel();
try
{
var max = 0;
if (_dbContext.OnlyTable.Any())
{
max = _dbContext.OnlyTable.Max(x => x.SomeColumn);
}
_dbContext.Add(new TestTable() { SomeColumn = max + 1 });
_dbContext.SaveChanges();
MakePostCallAsync("http:\\google.com", vm);
if (!string.IsNullOrEmpty(vm.TextToDisplay))
{
vm.TextToDisplay = "I have inserted the value " + newmax + " into table (-1 means error)";
}
else
{
vm.TextToDisplay = "Errored!";
}
}
catch (Exception ex)
{
vm.TextToDisplay = "I encountered error message - \"" + ex.Message + "\"";
}
return View("Index", vm);
}
private async void MakePostCallAsync(string url, ViewModel vm)
{
var httpClient = new HttpClient();
var httpResponse = await httpClient.PostAsync("http://google.com", null).ConfigureAwait(true);
newmax = _dbContext.OnlyTable.Max(x => x.SomeColumn);
}
问题在于,MakePostCallAsync() 方法在尝试使用 DbContext 查询数据库时,会引发异常,指出 DbContext 已被释放。
示例中的_dbContext 是使用 ASP .Net Core 的 DI(通过 AddDbContext() 扩展)及其默认范围 (Scoped) 注入的。
我无法理解以下内容并需要帮助,
- 为什么 DB 上下文在请求被处理之前就被释放了,而 Scoped 对象的生命周期应该是当前请求的整个持续时间
- 即使我使用了 ConfigureAwait(true)(这明确意味着一旦等待的方法返回 MakePostCallAsync() 应该在请求上下文中继续?) - 这似乎没有发生
- 在实际代码中,一旦我使所有方法异步(一直到控制器),这个问题就得到了修复 - 在我共享的 repro 中,即使这样也无助于防止异常 - 为什么会这样,如何我要解决这个问题吗?
Repro 在https://github.com/jjkcharles/SampleAsync 中可用
【问题讨论】:
标签: c# entity-framework asynchronous asp.net-core async-await