异步方法在等待语句返回后不会继续执行。

3

我正在使用MVC 4,并且我有以下代码:

    public void DoWork(string connectionId)
    {
        connectionId = this.connectionId;
        var a =  MakeADelayAsync();
    }

    public async Task MakeADelayAsync()
    {
        await Task.Delay(5000);
        var generalHubContext = GlobalHost.ConnectionManager.GetHubContext<GeneralHub>();
        generalHubContext.Clients.Client(connectionId).showNotification("Completed");
    }

"DoWork"方法是我的MVC操作。我的意图是当按下操作按钮时,“DoWork”调用一个异步方法并立即返回给客户端。当异步方法完成工作后,它将使用SignalR通知客户端。
问题在于“MakeADelayAsync”方法中,在等待之后的那两行代码永远不会被调用。似乎在await之后流程永远不会继续。
第一个问题是:“MakeADelayAsync”方法中的问题在哪里?
第二个问题是:为什么我必须编写无用的代码var a = MakeADelayAsync();以避免编译器警告,尽管我完全知道自己在做什么?我从来没有使用过“a”。

尝试在线程池中启动任务。类似于 Task.Factory.StartNew(MakeADelayAsync, TaskScheduler.Default)(从记忆中获取,可能签名有误)。 - Alxandr
Alex,我很感激你的帮助意愿,但那不是一个答案。即使它能够工作,也无法解释为什么await没有返回! - Pouyan
1
它未继续执行的原因可能是由于调度程序基于请求,而请求在await完成之前已结束。因此,在延迟后它不会调用继续操作(或者延迟本身被取消了)。在线程池上运行应该将您的方法调用与请求上下文隔离开来。至少这是理论。 - Alxandr
2个回答

1
"DoWork"方法是我的MVC操作。我的意图是当动作按钮被按下时,“DoWork”调用异步方法并立即返回给客户端。当异步方法完成工作后,它将使用SignalR通知客户端。 这样做非常危险。我强烈建议您像我在先前的答案中所说的那样使用持久队列:Azure队列、MSMQ、WebSphere MQ等。 但是,如果您坚持以危险的方式进行操作,则可以使用我在博客上的代码在ASP.NET请求上下文之外执行后台工作。"
public void DoWork(string connectionId)
{
    connectionId = this.connectionId;

    // This is extremely dangerous code! If ASP.NET unloads
    // your app, then MakeADelayAsync may not run to completion.
    BackgroundTaskManager.Run(() => MakeADelayAsync());
}

第一个问题是“MakeADelayAsync”中的问题在哪里?

您正在执行的代码尝试在请求完成并且请求上下文已处理后恢复请求上下文。这是您之前遇到的相同问题

第二个问题是,为什么我必须编写无用的 var a = MakeADelayAsync(); 代码以避免编译器警告,而我完全知道自己在做什么?

编译器警告告诉您代码几乎肯定是错误的... 而编译器是正确的。


0

你能尝试将你的DoWork方法标记为async吗?

public async void DoWork(string connectionId)
    {
        connectionId = this.connectionId;
        var a = MakeADelayAsync();
    }

我无法将我的Action标记为async,因为这将强制我等待一个语句。仅添加async而不等待任何内容是没有意义的。 - Pouyan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接