我是MVC C#中异步方法的新手,所以我尝试了This tutorial中的一些示例
因此,我使用保存creditcardtoken
public async Task<CreditCardToken> RegisterCardTokenAsync(CreditCardToken creditCardToken)
{
if (creditCardToken == null) return null;
creditCardToken.number = creditCardToken.maskedNumber;
_dbContext.CreditCardToken.Add(creditCardToken);
var saveChanges = await (_dbContext.SaveChangesAsync());
if (saveChanges > 0) return creditCardToken;
else return null;
}
我的控制器有一种方法可以调用我的registerCardTokenAsync
[HttpPost]
public ActionResult IngresarTargeta(CreditCardViewModel creditCardViewModel)
{
//do something here....
//do another thing....
var query = MyClass.RegisterCardTokenAsync(creditCardToken);
query.Wait();
}
理论上,我们使用query.Wait()
来“等待”直到操作完成。我的问题是CreditCardToken
已保存在数据库中,但是我的应用程序只是冻结了。
为什么会这样,我该如何解决?
据我所知,执行FirstOrDefaultAsync()
时需要等待。
答案 0 :(得分:5)
除非您完全了解上下文,否则不要同步等待async
调用,让async
传播。
public async Task<ActionResult> IngresarTargeta(CreditCardViewModel creditCardViewModel)
{
var result = await MyClass.RegisterCardTokenAsync(creditCardToken)
这就是为什么
顶级方法调用RegisterCardTokenAsync
(在ASP.NET上下文中)。
RegisterCardTokenAsync
通过调用_dbContext.SaveChangesAsync()
(仍在上下文中)开始保存更改。
SaveChangesAsync
返回未完成的Task
,表示保存未完成。
RegisterCardTokenAsync
等待Task
返回的SaveChangesAsync
。上下文被捕获,以后将用于继续运行SaveChangesAsync
方法。 SaveChangesAsync
返回未完成的Task
,表示SaveChangesAsync
方法不完整。
顶级方法在Task
返回的SaveChangesAsync
上同步阻止。这会阻塞上下文线程。
...
最终,SaveChangesAsync
将完成。这样就完成了Task
返回的SaveChangesAsync
。
RegisterCardTokenAsync
的延续现在可以运行了,它等待上下文可用(以便可以在上下文中执行)。
这将导致死锁。顶级方法正在阻止上下文线程等待RegisterCardTokenAsync
完成,而RegisterCardTokenAsync
正在等待上下文释放以便完成。
答案 1 :(得分:4)
理论上,您应该使所有功能异步
[HttpPost]
public async Task<ActionResult> IngresarTargeta(CreditCardViewModel creditCardViewModel)
{
//do something here....
//do another thing....
var token = await MyClass.RegisterCardTokenAsync(creditCardToken);
Ok(token);
}
非常好的资源:Don't Block on Async Code
请注意,在ASP.NET Core中,您的代码可以使用,因为它不使用SynchronizationContext。但是阻止异步方法仍然是错误的。