【发布时间】:2016-07-18 21:31:04
【问题描述】:
假设我正在编写一个自定义 MVC 过滤器,它在方法覆盖中执行一些异步调用,如下所示:
public class MyActionFilter : System.Web.Mvc.ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext ctx)
{
var stuff = ConfigureAwaitHelper1().Result;
// do stuff
}
public override void OnActionExecuting(ActionExecutingContext ctx)
{
var stuff = ConfigureAwaitHelper2().Result;
// do stuff
}
private async Task<string> ConfigureAwaitHelper1()
{
var result = await client.GetAsStringAsync("blah.com").ConfigureAwait(false);
return result;
}
private async Task<string> ConfigureAwaitHelper2()
{
return await client.GetAsStringAsync("blah.com").ConfigureAwait(false);
}
}
为什么OnActionExecuting 会死锁,而OnActionExecuted 不会?我看不出两者之间的根本区别。返回的行为只有在异步任务完成之后才会发生,这更像是在返回之前将结果放入“匿名返回”本地变量中,所以我不明白为什么前者会死锁。
【问题讨论】:
-
您在问“当我以一种方式违反规则时它不起作用,但当我以另一种方式违反规则时它确实有效,为什么我允许我以第二种方式违反规则”,答案是不是您不允许以第二种方式违反规则,您很幸运没有被发现违反规则。我不知道为什么第二个有效,但对我来说这并不重要,因为你不应该阻止它。
-
另外,为了让
.ConfigureAwait(false)真正让您执行.Result而不会死锁调用链中的每一个等待,必须在其上设置.ConfigureAwait(false)。如果一个没有,而那个 await 是导致 conintuation 发生的那个,你将陷入僵局。您需要显示client.GetAsStringAsync的代码及其下的每个 async/await 调用,直到找到仍然具有上下文数据的调用。 -
我有什么选择?
ActionFilterAttribute是同步的,我无法控制client。我知道您一直担心这样做,但让我们假设这个示例是完整的,并且在client.GetAsStringAsync()中没有任何进一步的配置。 -
你能仔细检查一下是
OnActionExecuting,而不是OnActionExecuted吗?
标签: c# asp.net-mvc async-await synchronizationcontext