如何更改异步方法调用以防止强制异步调用堆栈

如果我需要调用一个方法,在内部调用一些异步方法,作为一个fire and forget操作,我怎么能阻止这个调用强制“async”需要用完调用栈来说… MVC控制器?

例如:我的MVC控制器(非异步)调用业务层方法,该方法又调用Windows Azure Service Bus QueueClient.SendAsync(BrokeredMessage),将消息放入队列中,但不需要等待它完成。

通常,在调用此控制器操作时,编译器将抛出一个错误,指出此时无法启动异步操作。

我知道不是等待或只是调用SendAsync()方法,我可以使用ContinueWith()跟进它,以便在异步操作的回调上执行代码,但我被告知这不是一个正确的解决方案。 (请参阅对控制器中调用异步方法的响应)

有人会关心如何解决这种情况的最佳方法吗? 并告诉我为什么ContinueWith()方法不正确?

调用Windows Azure Service Bus QueueClient.SendAsync(BrokeredMessage),将消息放入队列中,但不需要等待它完成。

首先,我重新考虑这个假设。 如果您想要一个完全可靠的系统,该操作应该等待将消息发送到总线。 请注意,这通常是一个快速操作(100毫秒)。

通常,在调用此控制器操作时,编译器将抛出一个错误,指出此时无法启动异步操作。

确保您没有任何async void方法或EAP方法调用 。 如果Azure存储库导致该exception,我会非常惊讶。

有人会关心如何解决这种情况的最佳方法吗? 并告诉我为什么ContinueWith()方法不正确?

最好的解决方案是拥抱asyncContinueWith可以工作,但使用起来很危险(它有很多参数,其中一些参数有不安全的默认值); awaitContinueWith几乎相同,但没有危险的默认值。


但是,如果100ms确实无法忍受,并且您愿意放弃可靠性(在这种情况下,这意味着您接受这样的事实:即使操作成功完成,某些消息也可能无法发送到总线,因此客户认为他们做了 ),然后你可以使用我博客中的BackgroundTaskManager来减少丢失消息的可能性。

MVC控制器方法处理HTTP请求并将相应的HTTP响应发送回客户端。 如果我正确理解了您的问题,您希望从异步MVC控制器方法中调用即发即弃方法,然后继续执行HTTP响应传递,因此“即发即弃”方法不会保留响应。

实际上,您无法通过这种方式使用控制器方法触发它,而无需等待其结果。 即,您可以,但是如果您的ASP.NET应用程序将重新启动,或者IIS服务器从服务器场中取出,则永远不会调用您的ContinueWith回调。 所以,你不知道请求是否曾经到过Windows Azure服务。

解决此问题的一种方法是在同一主机上或同一网络上的另一台主机上运行辅助Web API或WCF服务(因此服务调用的转换将非常快)。 它可以是自托管服务。 您可以从MVC控制器调用此帮助程序服务,以便对即发即弃操作进行排队 。 您将await此调用的结果,但在这种情况下它不是问题,因为此操作的调用者和被调用者都将存在于同一网络上。

这样,原始的MVC HTTP响应将不会被搁置。 在帮助程序服务中,您将await QueueClient.SendAsync()调用Windows Azure Bus并相应地处理此操作的结果。