在异步函数上使用 await 时出现异常
Exception when using await on async function
我正在尝试使用 LinqToTwitter 从 ASP.NET CMS post 新闻文章到 Twitter。我已经创建了一个静态 class 来为我处理它,因为无论如何结果都会被记录下来并且不会影响网站的其余部分。但是,当我尝试 运行 它和 post 到 Twitter 时,出现异常:
System.InvalidOperationException: An asynchronous module or handler completed while an asynchronous operation was still pending
完整class:
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 的工具提示和文档中描述的功能。我知道 some 函数已完成,而另一个函数仍在 运行ning 但这不是 "await" 关键字的用途吗?
我尝试删除 PostTwitter 函数或故障点之后的代码,但结果仍然相同。我已经搜索了很多解决方案,但我可能在搜索或搜索错误方向时很糟糕。我什至在 SO 上注册只是为了问这个问题! :D
这里的罪魁祸首是您使用 async void 方法调用 Post:
internal static async void PostTwitter
Async void 函数仅用于事件处理,并且在该上下文之外使用时具有非常奇怪且不可预测的错误处理。有关信息,请参阅这篇 MSDN 文章。
将您的 async void 方法切换为 async Task 方法,一些实际错误可能会开始浮出水面:
internal static async Task PostTwitter
Stephen Cleary 实际上在另一篇文章 SO post 中非常详细地探讨了这个问题。直接引用他关于异步方法行为的内容:
Historically, ASP.NET has supported clean asynchronous operations since .NET 2.0 via the Event-based Asynchronous Pattern (EAP), in which asynchronous components notify the SynchronizationContext of their starting and completing
每当您的代码调用 SocialTwitter.PostTwitter 时,PostTwitter 方法会通知 SynchronizationContext 它已启动,完全绕过您正在使用的任何框架并直接进入 ASP.NET 核心. PostTwitter 方法会启动异步 Post 方法,该方法还会通知 SynchronizationContext 它已启动。
ASP.NET 框架了解如何等待任务,但是,在非常特殊的情况下,除了 WinForms 和 WebForms 之外,对如何处理 async void 方法知之甚少。因此,框架认为 async void 已完成,并尝试通知 SychronizationContext async void 方法已完成,即使 async void 方法生成了一个异步任务方法,该方法仍然是 运行。作为专门为捕获此类错误而设计的一系列安全网的一部分,SynchronizationContext 会抛出您已经看到的 InvalidOperationException。
我正在尝试使用 LinqToTwitter 从 ASP.NET CMS post 新闻文章到 Twitter。我已经创建了一个静态 class 来为我处理它,因为无论如何结果都会被记录下来并且不会影响网站的其余部分。但是,当我尝试 运行 它和 post 到 Twitter 时,出现异常:
System.InvalidOperationException: An asynchronous module or handler completed while an asynchronous operation was still pending
完整class:
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 的工具提示和文档中描述的功能。我知道 some 函数已完成,而另一个函数仍在 运行ning 但这不是 "await" 关键字的用途吗?
我尝试删除 PostTwitter 函数或故障点之后的代码,但结果仍然相同。我已经搜索了很多解决方案,但我可能在搜索或搜索错误方向时很糟糕。我什至在 SO 上注册只是为了问这个问题! :D
这里的罪魁祸首是您使用 async void 方法调用 Post:
internal static async void PostTwitter
Async void 函数仅用于事件处理,并且在该上下文之外使用时具有非常奇怪且不可预测的错误处理。有关信息,请参阅这篇 MSDN 文章。
将您的 async void 方法切换为 async Task 方法,一些实际错误可能会开始浮出水面:
internal static async Task PostTwitter
Stephen Cleary 实际上在另一篇文章 SO post 中非常详细地探讨了这个问题。直接引用他关于异步方法行为的内容:
Historically, ASP.NET has supported clean asynchronous operations since .NET 2.0 via the Event-based Asynchronous Pattern (EAP), in which asynchronous components notify the SynchronizationContext of their starting and completing
每当您的代码调用 SocialTwitter.PostTwitter 时,PostTwitter 方法会通知 SynchronizationContext 它已启动,完全绕过您正在使用的任何框架并直接进入 ASP.NET 核心. PostTwitter 方法会启动异步 Post 方法,该方法还会通知 SynchronizationContext 它已启动。
ASP.NET 框架了解如何等待任务,但是,在非常特殊的情况下,除了 WinForms 和 WebForms 之外,对如何处理 async void 方法知之甚少。因此,框架认为 async void 已完成,并尝试通知 SychronizationContext async void 方法已完成,即使 async void 方法生成了一个异步任务方法,该方法仍然是 运行。作为专门为捕获此类错误而设计的一系列安全网的一部分,SynchronizationContext 会抛出您已经看到的 InvalidOperationException。