jjk*_*les 2 c# asynchronous entity-framework async-await asp.net-core
在将现有同步方法转换为异步方法时,我不小心在其中一个方法上使用了“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);
}
Run Code Online (Sandbox Code Playgroud)
问题是,该MakePostCallAsync()
方法在尝试使用 DbContext 查询数据库时抛出异常,指出 DbContext 已被释放。
_dbContext
在示例中使用 ASP .Net Core 的 DI(通过 AddDbContext() 扩展)及其默认范围 (Scoped) 注入。
我未能并需要帮助理解以下内容,
async void
除非您正在编写事件处理程序,否则永远不要使用。如果您想使用 async/await,您需要一直向上调用堆栈,直到返回一个Task<IActionResult>
public async Task<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();
await 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 Task 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);
}
Run Code Online (Sandbox Code Playgroud)
在您的示例中,您没有等待您的电话MakePostCallAsync("http:\\google.com", vm)
。这意味着请求会立即继续执行,并最终执行处理您的 的代码_dbContext
,大概MakePostCallAsync
是在等待 HTTP 客户端返回响应的同时。一旦 HTTP 客户端返回响应,您MakePostCallAsync
将尝试调用newmax = _dbContext.OnlyTable.Max(x => x.SomeColumn)
,但您的请求已被处理,并且您的数据库上下文届时已被处理。