【问题标题】:How to use AsyncPostBackTrigger to trigger functions from the backend to show progress bar on the front-end?如何使用 AsyncPostBackTrigger 从后端触发函数以在前端显示进度条?
【发布时间】:2026-02-11 05:10:01
【问题描述】:

每当执行后端的函数时,我都会使用 UpdatePanel 来填充进度条。用户首先必须上传一个 csv 文件。一旦 csv 文件被上传并临时保存,用户然后按下另一个按钮(我们称之为“更新和查看”),该按钮运行一系列函数来清理 csv 文件并将其转换为 json 文件。一些 csv 文件很大,很难判断 csv 在执行时运行的是哪个函数。

但是,问题是每次用户按下“更新和查看”按钮时,什么都没有发生。我从控制台收到一个错误,指出对象引用未设置为对象的实例。

由于我的按钮在 UpdatePanel 之外,所以我确保在 UpdatePanel 中进行了设置。我确定了 EventName="click"。对于 UpdatePanel,我确定了我的 UpdateMode="Conditional",因为我只希望在函数完成运行时填充进度条。我设置了 ChildrenAsTriggers="true" - 是否将此设置更改为“false”并不重要。按钮仍然没有执行我做的功能。此外,我在我的 aspx 页面中确保 Async="true"。我使用 asp:AsyncPostBackTriggers 而不是 asp:PostBackTriggers。我想知道这是否是问题所在,但我不相信这是因为我试图在更新前端进度条的同时运行后端。下面是来自后端(vb)的示例代码和来自前端的示例代码。

 Protected Sub BtnUpload_Click(sender As Object, e As EventArgs)

    statusLabel.Text = ""

    While statusLabel.Text = ""
        statusLabel.Text = Test_CSV()
        Try
            loadbar.Style("width") = "10%"
            updateP.Update()
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
        statusLabel.Text = Save_CSV()

        statusLabel.Text = Create_tables("fileOne")


        statusLabel.Text = Transfer_Tables("fileOne")


        statusLabel.Text = Update_Tables("fileOne")

        statusLabel.Text = Query_JSON()



    End While

    FileUploadControl.Enabled = False
    BtnUpload.Enabled = False
    FileUploadControl.Visible = False
    BtnUpload.Visible = False


    Response.Redirect("/summary/filesummary.aspx")


End Sub
  <div class="row" style="padding-left: 0; padding-top: .5em;">
    <div class="col-md-12">
        <label class="file-upload">
            <span id="selectcsv" runat="server">Select CSV File                   
                 <asp:FileUpload ID="FileUploadControl" runat="server"                        
       onchange="document.getElementById('uploadText').style.display =            
    'block';showFile();document.getElementById('instruction').style.display = 
   'none';" CssClass="hidden" /></span>
        </label>
    </div>
</div>

<div class="row" style="margin-bottom: 1em;">
    <div class="col-md-12">
        <label class="file-upload" id="uploadText" style="display: none;">
            <span>Update and view results</span>
            <asp:Button runat="server" ID="BtnUpload" OnClick="BtnUpload_Click" CssClass="hidden"/>
        </label>
        <asp:Label CssClass="label" runat="server" ID="statusLabel"></asp:Label>
    </div>
</div>


    <asp:UpdatePanel id="updateP" runat="server" UpdateMode="Conditional" 
               ChildrenAsTriggers="false">
        <ContentTemplate>
            <div role="progressbar" class="progress-bar" id="loadbar" 
            style="width: 0%" aria-valuemin="0" aria-valuemax="100" 
             runat="server"></div>
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="BtnUpload" 
             EventName="click" runat="server"/>
        </Triggers>
    </asp:UpdatePanel>

我放了一个 try/catch 语句,看看能否得到更详细的错误框,但什么也没出现。我至少希望我的进度条填充 10%(它基于宽度的样式属性。我没有详细显示任何 css 类,但是当您更改宽度时,进度条会着色)。但是,再次没有发生任何事情我有错误在哪里

对象引用未设置为对象的实例。

错误发生在 MAjax 的第 1 行。我不确定这意味着什么。

【问题讨论】:

  • 代码MAjax在哪里
  • 这是您检查页面时出现的错误。就是这样:Sys.WebForms.PageRequestManagerServerErrorException:对象引用未设置为对象的实例。在 Function.Error.create (MsAjaxJs?v=D6VN0fHlwFSIWjbVzi6mZyE9Ls-4LNrSSYVGRU46XF81:1)

标签: javascript sql-server vb.net asynchronous


【解决方案1】:
  1. 我在您的设计文件中没有看到任何 FileUploadControl。

  2. updateP.Update 不要立即在您的前端发送更改的 html。它将仅在页面处理结束时发送。您需要使用一个计时器,该计时器将在服务器上发送异步请求并获取当前的上传状态。我在分离的线程上运行上传文件。由于它在服务器上启用并启动了计时器,而无需额外的客户端代码。而且我已经使用运行时缓存来存储工作状态。


<div class="row" style="margin-bottom: 1em;">
        <div class="col-md-12">
            <label class="file-upload" id="uploadText">
                <span>Update and view results</span>
                <asp:Button runat="server" ID="btnConvert" OnClick="btnConvert_Click" CssClass="hidden" />
            </label>
            <asp:Label CssClass="label" runat="server" ID="statusLabel"></asp:Label>
        </div>
    </div>

    <div class="row" style="margin-bottom: 1em;">
        <div class="col-md-3">
            <asp:FileUpload ID="fileUpload1" runat="server" />            
        </div>
        <div class="col-md-9">
            <asp:Button ID="btnUploadFile" Text="Upload file" runat="server" OnClick="btnUploadFile_Click" />
        </div>
    </div>

    <asp:Timer ID="timerGetStatus" runat="server" Interval="1000" OnTick="timerGetStatus_Tick" Enabled="false"></asp:Timer>

    <asp:UpdatePanel ID="updateP" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="false">
        <ContentTemplate>
            <div class="row">
                <div class="progress">
                    <div id="loadbar" runat="server" class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
                </div>
            </div>
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="timerGetStatus" EventName="Tick" runat="server" />
        </Triggers>
    </asp:UpdatePanel>


Imports System.Threading
Imports System.Threading.Tasks

Public Class _Default
    Inherits Page

    Public Property FileId As Guid?
        Get
            Return CType(ViewState("FileId"), Guid?)
        End Get
        Set(ByVal value As Guid?)
            ViewState("FileId") = value
        End Set
    End Property

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
    End Sub

    Protected Sub btnConvert_Click(ByVal sender As Object, ByVal e As EventArgs)
        Task.Run(
            Sub()
                ConvertFile(FileId.Value)
            End Sub)
        timerGetStatus.Enabled = True
    End Sub

    Private Sub ConvertFile(ByVal workId As Guid)
        Save_CSV()
        Create_tables()
        Transfer_Tables()
        Update_Tables()
        Query_JSON()
    End Sub

    Private Sub Save_CSV()
        Dim text As String = GetFile()
        Thread.Sleep(1000)
        ChangeProgress(20)
    End Sub

    Private Sub Create_tables()
        Dim text As String = GetFile()
        Thread.Sleep(3000)
        ChangeProgress(30)
    End Sub

    Private Sub Transfer_Tables()
        Dim text As String = GetFile()
        Thread.Sleep(2000)
        ChangeProgress(50)
    End Sub

    Private Sub Update_Tables()
        Dim text As String = GetFile()
        Thread.Sleep(6000)
        ChangeProgress(80)
    End Sub

    Private Sub Query_JSON()
        Dim text As String = GetFile()
        Thread.Sleep(4000)
        ChangeProgress(100)
    End Sub

    Protected Sub timerGetStatus_Tick(ByVal sender As Object, ByVal e As EventArgs)
        ShowProgress()
        If GetProgress() = 100 Then
            timerGetStatus.Enabled = False
        End If
    End Sub

    Protected Sub btnUploadFile_Click(sender As Object, e As EventArgs)
        FileId = Guid.NewGuid()
        Cache($"File_{FileId}") = fileUpload1.FileBytes
        ChangeProgress(10)
        ShowProgress()
    End Sub

    Private Function GetFile() As String
        Return Encoding.UTF8.GetString(Cache($"File_{FileId}"))
    End Function

    Private Sub ChangeProgress(progress As Integer)
        Cache($"Progress_{FileId.Value}") = progress
    End Sub

    Private Function GetProgress() As Integer
        Return Cache($"Progress_{FileId.Value}")
    End Function

    Private Sub ShowProgress()
        If FileId.HasValue Then
            loadbar.Style.Add("Width", $"{GetProgress()}%")
        End If
    End Sub
End Class

【讨论】:

  • 感谢您的回复!现在这对 Update() 有意义。是的,我没有使用 FileUploadControl 显示前端,但它在我的完整代码中。我将编辑此问题中的代码以反映它。我会试用你写的代码,如果它有助于解决问题,我会告诉你。
  • 计时器是个好主意,但我不想计算上传文件需要多长时间。我试图显示使用原始问题中显示的函数转换文件需要多长时间。用户首先上传一个文件。这是快速的部分。但是,当您单击“BtnUpload”时,用户必须按下另一个按钮,该按钮将通过 6 个不同的功能运行上传的文件(抱歉不是最佳命名约定)。我将通过 Task.Run 运行什么?如果您需要我澄清,请告诉我!谢谢!
  • @Aileen Timer 是个好主意。我通过简单的方式更新了示例:添加了转换阶段以说明如何在文件过程中通知用户有关更改的主要想法。
  • 谢谢瓦西尔!我会再试一次。
  • @Aileen 我很乐意提供帮助
最近更新 更多