在ASP.NET中调用异步方法时的行为混乱 [英] Confusing behaviour when invoking async methods inside ASP.NET

查看:172
本文介绍了在ASP.NET中调用异步方法时的行为混乱的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Visual Studio 2012创建了一个ASP WebApplication.

I created an ASP WebApplication using Visual Studio 2012.

如果我如下修改默认页面:

If I modify the default page as follows:

public partial class _Default : Page
{
    static async Task PerformSleepingTask()
    {
        Action action = () =>
        {
            Thread.Sleep(TimeSpan.FromSeconds(0.5));
            int dummy = 3; // Just a nice place to put a break point
        };
        await Task.Run(action);
    }


    protected void Page_Load(object sender, EventArgs e)
    {
        Task performSleepingTask = PerformSleepingTask();
        performSleepingTask.Wait();
    }
}

在呼叫performSleepingTask.Wait()时,它会无限期挂起.

On the call to performSleepingTask.Wait() it hangs indefinitely.


有趣的是,如果我在web.config中进行设置:


Interestingly, if I set this in the web.config:

<appSettings>

    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="false" />
</appSettings>

然后它可以工作. Wait函数等待休眠在其他线程上完成,然后继续.

Then it does work. The Wait function waits for the sleeping to finish on a different thread, then continues.

有人可以解释:

  • 为什么挂起?
  • 为什么他们有一个叫TaskFriendlySynchronizationContext的东西? (鉴于它导致任务挂起,我不会称其为友好的")
  • Why does it hang?
  • Why do they have something called TaskFriendlySynchronizationContext? (Given that it causes tasks to hang, I wouldn't call it "friendly")
  • 是否存在从页面处理程序方法中调用async方法的最佳实践"?
  • Is there a "best practice" for invoking async methods from page handler methods?

这是我想出的一个可行的实现,但是感觉像笨拙的代码:

Here's an implementation I came up with which works, but it feels like clumsy code:

    protected void Page_Load(object sender, EventArgs e)
    {
        ManualResetEvent mre = new ManualResetEvent(false);
        Action act = () =>
        {
            Task performSleepingTask = PerformSleepingTask();
            performSleepingTask.Wait();
            mre.Set();
        };
        act.BeginInvoke(null, null);
        mre.WaitOne(TimeSpan.FromSeconds(1.0));
    }

推荐答案

为什么挂起?

Why does it hang?

表示PerformSleepingTaskTask在其await之后尝试恢复,以便PerformSleepingTask可以返回.它正在尝试重新输入ASP.NET请求上下文,该上下文被调用Wait阻止. 这会导致僵局,正如我在博客中所阐述的那样.

The Task representing PerformSleepingTask is trying to resume after its await so that PerformSleepingTask can return. It is trying to re-enter the ASP.NET request context, which is blocked by the call to Wait. This causes a deadlock, as I expound on my blog.

为避免僵局,请遵循以下最佳实践:

To avoid the deadlock, follow these best practices:

  1. 完全使用async.不要阻塞async代码.
  2. 在您的库"方法中使用ConfigureAwait(false).
  1. Use async all the way down. Don't block on async code.
  2. Use ConfigureAwait(false) in your "library" methods.

为什么他们有一个叫TaskFriendlySynchronizationContext的东西? (鉴于它导致任务挂起,我不会称其为友好的")

Why do they have something called TaskFriendlySynchronizationContext? (Given that it causes tasks to hang, I wouldn't call it "friendly")

TaskFriendlySynchronizationContext使用新的AspNetSynchronizationContext(.NET 4.0 TaskFriendlySynchronizationContext已重命名为LegacyTaskFriendlySynchronizationContext),并且还使用了一个新的可识别async的管道.

TaskFriendlySynchronizationContext uses the new AspNetSynchronizationContext (the .NET 4.0 TaskFriendlySynchronizationContext has been renamed LegacyTaskFriendlySynchronizationContext), and it also uses a new, async-aware pipeline.

我不确定是否对此有100%的把握,但我怀疑认为Page_Load适用于旧版SyncCtx的原因是旧管道尚未将SyncCtx放置到位.我不知道为什么会这样操作(除非Page.Asyncfalse).

I'm not 100% sure about this one, but I suspect that the reason Page_Load works for the legacy SyncCtx is that the old pipeline wasn't putting the SyncCtx in place yet. I'm not sure why it would act this way, though (unless Page.Async was false).

是否存在从页面处理程序方法中调用异步方法的最佳实践"?

Is there a "best practice" for invoking async methods from page handler methods?

绝对.您可以使事件处理程序为async void,也可以使用RegisterAsyncTask(new PageAsyncTask(...));.第一种方法比较容易,但是第二种方法受到ASP.NET团队的青睐.

Absolutely. You can either just make your event handlers async void, or use RegisterAsyncTask(new PageAsyncTask(...));. The first approach is easier but the second approach is favored by the ASP.NET team.

这篇关于在ASP.NET中调用异步方法时的行为混乱的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆