【问题标题】:Not able to update UI after background task completion in my ASP.NET application在我的 ASP.NET 应用程序中完成后台任务后无法更新 UI
【发布时间】:2022-01-02 07:27:40
【问题描述】:

我在我的 asp.net 应用程序中运行一个长时间运行的函数作为后台任务。在任务完成之前,主线程退出(我只希望这样,因为如果我使用 await 关键字并使主线程等待后台任务完成,我会收到带有消息的代理错误

代理错误
由于后台任务太长,代理服务器收到来自上游服务器的无效响应

但是一旦任务完成后,我既不能通过重定向到同一页面来刷新页面,也不能覆盖 UI。主线程执行完成后有什么方法可以更新 UI。

我的代码是这样的:

protected void btnImport_Click(object sender, EventArgs e)
{
        var task = ImportThread();

        if (task.IsCompleted)
        {
            DisplaySuccess("Import success");
        }
        else
            DisplayError("Import failed");
}

private async Task<bool> ImportThread()
{
        try
        {
            var success = await Task<bool>.Run(() => new Manager().Import().ConfigureAwait(false);

            if (task.IsCompleted)
            {
                DisplaySuccess("Import success");
            }
            else 
            {
                DisplayError("Import failed");
            }
    
            return true;
}

上面的异步任务等待另一个类中存在的下面的方法。

public bool Import()
{
    // some operations here
    return true;
}

此方法完成后,控件返回到ImportThread(),但那里编写的用于覆盖 UI 的代码不会更新 UI。我需要使用导入状态更新 UI。而且来自ImportThread 的控件也不会返回到按钮单击事件方法。

请帮助我以任何方式更新 UI 导入状态。

注意:我尝试在ImportThread() 中使用Redirect.Response 来刷新页面,但这不起作用

【问题讨论】:

  • 这永远不会奏效,因为您缺少关键的理解。您正在创建一个后台线程,当它完成时,已经没有 HttpRequest 了!您无法重定向用户或更新任何内容,原因很简单,即没有用户。

标签: c# asp.net async-await task-parallel-library background-task


【解决方案1】:

你的问题是你必须掌握和理解这里的网页生命周期。

您有这种网页位于用户桌面上的情况:

现在假设用户点击了一个按钮。

你现在有了这个:

 var task = ImportThread();

    if (task.IsCompleted)

好的,所以网页在服务器上。你甚至可以设置异步等待,直到奶牛回家,但你仍然有这个:

所以只要您的代码运行或等待,网页仍然在服务器端卡住。只有在代码完成并退出之前,页面才会向下移动到客户端。

再次: 您后面的代码不能停止,也不能等待某些事情完成,因为如果它停止了,那么页面会一直在服务器上,直到处理完成。

然后,只有在那时,网页才会返回客户端。然后发生这种情况;

然后服务器端页面被抛出内存,所有类变量都被销毁!!! Web 服务器现在正在等待任何用户发回页面以进行处理!

那么,如果您需要运行某种长时间运行的进程?

你有几个选择:

发布页面,后台代码运行,后台代码启动一个新线程,网页返回客户端。此时,您需要一个计时器 + 某种类型的 Web 方法调用 (ajax) 来轮询或询问服务器是否完成了长时间运行的进程。并且由于 ajax 调用没有使用该页面上的任何 Web 控件或页面类变量(请记住,在网页返回客户端之后,该网页在内存中不存在 Web 服务器端,也不是任何存在的类变量)。所以,再一次,这在很大程度上意味着某种计时器,或者如前所述,一个计时器+代码来调用一些 ajax 方法。并且那个长时间运行的进程很可能必须使用 session(),因为你没有使用控件,甚至没有 ViewState。

而且您不必使用 ajax 调用。您可以使用带有计时器的简单 JavaScript 客户端例程,表示每 1 或 2 秒单击一次按钮,运行背后的代码,然后它必须获取该长时间运行进程的状态(同样可能来自会话),并且然后更新显示。然后您还可以包含代码以在状态更改为“完成”或其他任何内容时停止计时器。

所以后面的代码不会也不会多次“更新”网页。你有一个往返,后面的代码必须运行得很快,必须完成运行,甚至不能使用 AWAIT 命令,因为那时页面将一直等待,并且仍然卡在服务器上。

如果您想超越我经常使用的简单计时器技巧方法?

那么您需要采用并在您的网站中引入为此类案例设计的东西-

值得庆幸的是,有用于此目的的 signalR,这无疑是您的最佳选择和方法,因为它正是针对您的问题和场景而设计的。

信号R

https://docs.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr#:~:text=What%20is%20SignalR%3F%20ASP.NET%20SignalR%20is%20a%20library,process%20of%20adding%20real-time%20web%20functionality%20to%20applications.

【讨论】:

    【解决方案2】:

    如果您想异步通知用户(任务完成或失败),您可以使用网络推送通知(使用 firebase 消息传递云)或 SignalR 套接字。当您使用后台任务时,您会失去主线程,不幸的是,无法响应相关用户。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-03
      • 1970-01-01
      • 2015-07-20
      • 1970-01-01
      • 2012-06-15
      • 2023-03-15
      • 2013-10-08
      相关资源
      最近更新 更多