我使用了async
方法来卸载几秒钟'值得一劳永逸的工作,以免减慢我的页面负载。这项工作需要一些整体设置和整理;我希望(快速)设置在抛出时同步抛出,但我不想强制整理在ASP上下文中运行,所以我在我正在等待的位上使用ConfigureAwait
:
public Task FireAndForget()
{
DoSetup();
return FireAndForgetAfterSetup();
}
private async Task FireAndForgetAfterSetup()
{
await AFewSecondsWorthOfWork().ConfigureAwait(false);
DoTidyUp();
}
protected void btn_Click(object sender, EventArgs e)
{
FireAndForget();
}
这看起来很奇怪,因为
FireAndForgetAfterSetup
不应该关心是否从ASP上下文调用它,那么为什么要调用ConfigureAwait
呢?btn_Click
应该等待FireAndForget
完成,是否已经抛弃了ASP上下文(?)如果我有误解,有人可以向我解释一下吗?
答案 0 :(得分:3)
ASP.NET同步上下文不允许在请求中启动“即发即忘”工作项。运行时会主动监视这些事情并尝试生成异常,因为这些代码模式会导致null refs,死锁,AV和其他恶意。
如果您绝对需要在ASP.NET中启动“即发即弃”工作,请考虑使用WebBackgrounder。它集成了ASP.NET扩展点,旨在实现此目的。所以它不会阻止有效请求,但要记住斯蒂芬的警告:它并不能保证在所有中执行。如果您需要保证执行,请考虑像Service Bus这样的可靠性机制。
答案 1 :(得分:1)
如果您的方案是如何在加载期间执行某些(相对)长时间运行的任务,则ASP.NET允许此方案通过Page.RegisterAsyncTask方法。 Scott Hansleman描述了如何在The Magic of using Asynchronous Methods in ASP.NET 4.5 plus an important gotcha
中使用它基本上,您创建一个返回Task并调用的异步方法:
RegisterAsyncTask(new PageAsyncTask(MyAsyncMethod));
然后调用Page.ExecuteRegisteredAsyncTasks开始执行所有已注册的任务。
Scott Hanselman(当然)做了很好的描述为什么使用事件处理程序,任务或后台线程是一个坏主意。
“异步页面事件”部分的“What Not to do in ASP.NET, What to do instead”中也对此进行了描述
答案 2 :(得分:0)
我不确定为什么他没有发布,但我的确切的两个问题在this blog post by Stephen Cleary得到解答:
这个例子需要注意的重点是每个"等级"异步方法调用有自己的上下文。 DownloadFileButton_Click在UI上下文中启动,并称为DownloadFileAsync。 DownloadFileAsync也在UI上下文中启动,但随后通过调用ConfigureAwait(false)退出其上下文。 DownloadFileAsync的其余部分在线程池上下文中运行。但是,当DownloadFileAsync完成并且DownloadFileButton_Click恢复时,它会在UI上下文中恢复。
一个好的经验法则是使用ConfigureAwait(false),除非你知道你确实需要上下文。
ConfigureAwait(false)
知道他们不会使用上下文,因为... < / LI>
async
方法抛弃了UI上下文,调用方法仍然有自己的副本。因此调用方法可以await
库方法并在UI上下文中恢复......但是当发生这种情况时它会发生死锁。