C# 未等待时配置等待

C# 未等待时配置等待,c#,asp.net,async-await,synchronizationcontext,azure-webjobs,C#,Asp.net,Async Await,Synchronizationcontext,Azure Webjobs,我有一个async方法,我用它来减轻几秒钟的工作量,忘记工作,以免减慢页面加载速度。这项工作需要一些一般的设置和整理;如果抛出,我希望(fast)设置同步抛出,但我不想强制整理在ASP上下文中运行,因此我在等待的位上使用ConfigureAwait: public Task FireAndForget() { DoSetup(); return FireAndForgetAfterSetup(); } private async Task FireAndForgetAfterS

我有一个
async
方法,我用它来减轻几秒钟的工作量,忘记工作,以免减慢页面加载速度。这项工作需要一些一般的设置和整理;如果抛出,我希望(fast)设置同步抛出,但我不想强制整理在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上下文(?)

如果我有误解,有人能给我解释一下吗?

ASP.NET同步上下文不允许在请求中启动并忘记工作项。运行时会主动监视这些事情,并尝试生成异常,因为这些代码模式会导致空引用、死锁、AV和其他不好的情况


如果你真的需要开火,忘记在ASP.NET工作,考虑使用。它与ASP.NET扩展点集成,这些扩展点旨在实现这一点。因此,它不会阻止活动请求,但请记住Stephen的警告:它根本不能保证被执行。如果需要保证执行,请考虑像服务总线这样的可靠性机制。

< P> ASP.NET同步上下文不允许在请求内开火和忘记工作项。运行时会主动监视这些事情,并尝试生成异常,因为这些代码模式会导致空引用、死锁、AV和其他不好的情况


如果你真的需要开火,忘记在ASP.NET工作,考虑使用。它与ASP.NET扩展点集成,这些扩展点旨在实现这一点。因此,它不会阻止活动请求,但请记住Stephen的警告:它根本不能保证被执行。如果需要保证执行,请考虑一个可靠性机制,如Service BUS。

< P>如果您的场景是如何在加载期间执行一些(相对)长时间运行的任务,那么ASP.NET通过该方法允许该场景。Scott Hansleman介绍了如何在中使用它

本质上,您创建了一个异步方法,该方法返回任务和调用:

RegisterAsyncTask(new PageAsyncTask(MyAsyncMethod));
然后调用以开始执行所有已注册的任务

Scott Hanselman(当然)很好地描述了为什么使用事件处理程序、任务或后台线程是个坏主意


这在“异步页面事件”部分的“”中也有描述。如果您的场景是如何在加载期间执行一些(相对)长时间运行的任务,ASP.NET允许通过该方法执行此场景。Scott Hansleman介绍了如何在中使用它

本质上,您创建了一个异步方法,该方法返回任务和调用:

RegisterAsyncTask(new PageAsyncTask(MyAsyncMethod));
然后调用以开始执行所有已注册的任务

Scott Hanselman(当然)很好地描述了为什么使用事件处理程序、任务或后台线程是个坏主意


在“异步页面事件”部分的“”中也描述了这一点,我不确定他为什么没有发布它,但我的两个问题在中得到了回答:

本例中需要注意的重要一点是,异步方法调用的每个“级别”都有自己的上下文。DownloadFileButton\单击在UI上下文中启动,并调用DownloadFileAsync。DownloadFileAsync也在UI上下文中启动,但随后通过调用ConfigureAwait(false)退出其上下文。DownloadFileAsync的其余部分在线程池上下文中运行。但是,当DownloadFileAsync完成并单击DownloadFileButton_恢复时,它会在UI上下文中恢复

一个好的经验法则是使用ConfigureAwait(false),除非您知道确实需要上下文

  • 在回答我的第一个要点时,是的,在库方法中使用
    ConfigureAwait(false)
    是可以的(鼓励!),因为
  • 。。。在回答我的第二个要点时,即使库
    async
    方法丢弃了UI上下文,调用方法仍然有自己的副本。因此,调用方法可以等待库方法,并在UI上下文中恢复。。。但当这种情况发生时,它将陷入僵局

我不知道他为什么不发布,但我的两个问题在中得到了回答:

本例中需要注意的重要一点是,异步方法调用的每个“级别”都有自己的上下文。DownloadFileButton\单击在UI上下文中启动,并调用DownloadFileAsync。DownloadFileAsync也在UI上下文中启动,但随后通过调用ConfigureAwait(false)退出其上下文。DownloadFileAsync的其余部分在线程池上下文中运行。但是,当DownloadFileAsync完成并单击DownloadFileButton_恢复时,它会在UI上下文中恢复

一个好的经验法则是使用ConfigureAwait(false),除非您知道确实需要上下文

  • 在回答我的第一个要点时,是的,在库方法中使用
    ConfigureAwait(false)
    是可以的(鼓励!),因为
  • 。。。在回答我的第二个要点时,即使库
    async
    方法丢弃了UI上下文,调用方法仍然有自己的副本。因此,调用方法可以等待库方法,并在UI上下文中恢复。。。但当这种情况发生时,它将陷入僵局
目前,您的代码根本不会同步抛出。返回的任务将出错,但不会引发异常。我首先要解决这个问题:)你知道ASP.NET上的“发射并忘记”实际上意味着“我不在乎这个代码是否真的被执行了”吗?你绝对肯定你是个骗子吗