我正在尝试使用LinqToTwitter从ASP.NET CMS向Twitter发布新闻文章。我已经创建了一个静态类,它将为我处理它,因为结果将被记录,并且不会影响网站的其余部分。但是,当我尝试运行它并发布到Twitter时,会发生异常:
System.InvalidOperationException:在异步操作仍处于挂起状态时完成异步模块或处理程序
全班:
public static class SocialTwitter
{
internal async static void PostTwitter(string message)
{
await Post(message);
}
private async static Task Post(string message)
{
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["TwitterConsumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["TwitterConsumerSecret"],
AccessToken = ConfigurationManager.AppSettings["TwitterToken"],
AccessTokenSecret = ConfigurationManager.AppSettings["TwitterTokenSecret"]
}
};
await auth.AuthorizeAsync();
TwitterContext t = new TwitterContext(auth);
//Exception occurs here
Status tweet = await t.TweetAsync(Uri.EscapeDataString(message));
if (tweet != null)
{
Util.Log.Info(string.Format("Status posted: ({0}) {1}, {2}", tweet.StatusID, tweet.User.Name, tweet.Text));
}
else
{
Util.Log.Info("Error occurred posting status to Twitter");
}
}
}
奇怪的部分(至少对我来说)是我使用LinqToTwitter的工具提示和文档中描述的功能。我得到某些函数已完成,而另一个函数仍在运行,但这不是“await”关键字的用途吗?
我尝试在故障点之后切断PostTwitter功能或代码,但结果仍然相同。我已经搜索了很多解决方案,但我可能只是在搜索或搜索错误的方向时很糟糕。我甚至在SO上注册只是为了提出这个问题! :d
答案 0 :(得分:3)
这里的罪魁祸首是您使用异步void方法调用Post:
internal static async void PostTwitter
Async void函数仅用于事件处理,并且在此上下文之外使用时具有非常奇怪和不可预测的错误处理。有关信息,请参阅此MSDN文章。
将async void方法切换为异步任务方法,并且一些实际错误可能会开始冒泡到表面:
internal static async Task PostTwitter
Stephen Cleary实际上在另一篇SO帖子中详细讨论了这个问题。直接引用他关于异步方法的行为:
从历史上看,ASP.NET通过基于事件的异步模式(EAP)支持自.NET 2.0以来的干净异步操作,其中异步组件通知SynchronizationContext它们的开始和完成
每当您的代码调用SocialTwitter.PostTwitter时,PostTwitter方法会通知SynchronizationContext它已启动,绕过您完全使用的任何框架并直接进入ASP.NET核心。 PostTwitter方法比启动异步Post方法,该方法还通知SynchronizationContext它已经启动。
ASP.NET框架了解如何等待Tasks,但是,在非常特定的情况下排除WinForms和WebForms,对如何处理异步void方法知之甚少。因此,框架认为async void是完整的,并且它尝试通知SychronizationContext async void方法已完成,即使async void方法产生了仍在运行的异步Task方法。作为专门用于捕获此类错误的一系列安全网的一部分,SynchronizationContext会抛出您已经看到的InvalidOperationException。