11

I have used a piece of simple code from this helpful post

It uses a button and a label, the label should report "10% completed"... "20% completed"... and so on.

When I debug, the code is getting hit, but my label is not updating on the browser.

I have tried with & without update panels, with and without a masterpage.

protected void btnStartThread_Click(object sender, EventArgs e)
    {
        BackgroundWorker bw = new BackgroundWorker();

        // this allows our worker to report progress during work
        bw.WorkerReportsProgress = true;

        // what to do in the background thread
        bw.DoWork += new DoWorkEventHandler(delegate(object o, DoWorkEventArgs args)
        {
            BackgroundWorker b = o as BackgroundWorker;

            // do some simple processing for 10 seconds
            for (int i = 1; i <= 10; i++)
            {
                // report the progress in percent
                b.ReportProgress(i * 10);
                Thread.Sleep(1000);
            }
        });



        // what to do when progress changed (update the progress bar for example)
        bw.ProgressChanged += new ProgressChangedEventHandler(delegate(object o, ProgressChangedEventArgs args)
        {
            label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
        });


        // what to do when worker completes its task (notify the user)
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
        delegate(object o, RunWorkerCompletedEventArgs args)
        {
            label1.Text = "Finished!";
        });

        bw.RunWorkerAsync();
Community
  • 1
  • 1
wotney
  • 1,039
  • 3
  • 21
  • 34
  • 9
    If the HTML has already been sent to the client over the network, how do you expect to be able to update it? You need to be using AJAX on the client to update the page. – Martin Costello Apr 29 '14 at 12:33
  • Which is why I thought a script manager & update panel on the page would do the trick :/ – wotney Apr 29 '14 at 12:34
  • It should. I can't remember completely, are you sure you don't need to call something like updatePanel.Update(); or similar? – Falgantil Apr 29 '14 at 12:35
  • 3
    You'll need to use something like SignalR to send that signal to the client. – Mike Perrenoud Apr 29 '14 at 12:36
  • @BjarkeSøgaard - I have basically the same code, but my progresschanged handler is doing an updatePanel.Update(). It still does not work. I even have a 100ms timer on the update panel to cause it to do a partial page postback to update the panel every 100ms, but it simply does not do it. This long running task seems to keep the UI from doing absolutely anything until it is completed. –  Oct 28 '15 at 15:27
  • 2
    In client server web appalication, server doesn't initiate communication with client, it only responds to client's requests. You can achieve what you want with client pulling mode by using ajax requests or server push mode with signalr http://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-net-client – lyz Oct 29 '15 at 15:23

4 Answers4

5

You could potentially do long polling to get your updated result. Personally I wouldnt use a background worker in a Web application. Also, consider looking at SignalR, Server Sent Events and Async and Await or the Task Parallel Library.

brumScouse
  • 3,166
  • 1
  • 24
  • 38
  • A little helpful, but not much of an answer. I really need to figure out how to get updates back to the webpage, back to the user, in the middle of a long running task. –  Oct 28 '15 at 14:38
4

BackgroundWorker is not suitable for ASP.NET and doesn't work with ASP.NET very well because ASP.NET works on a request/response model. To receive any updates the client's browser needs to request the information from the server. For example for your Label to be updated you will need to send a request for its new value to the server.

One option could be using AJAX for this purpose on the client to update the page. But rather than use formal AJAX, You can using an iframe that is a great way to asynchronously execute the long running process, without being dependent on any particular AJAX framework. When the button is clicked, an invisible iframe is dynamically generated and used to execute LongRunningProcess.aspx in the background:

<head runat="server">
<script type="text/javascript">
    function BeginProcess() {
        var iframe = document.createElement("iframe");
        iframe.src = "LongRunningProcess.aspx";
        iframe.style.display = "none";
        document.body.appendChild(iframe);
        document.getElementById('trigger').disabled = true;
    }

    function UpdateProgress(PercentComplete, Message) {
        document.getElementById('<%= Label1.ClientID %>').innerHTML = PercentComplete + '% ' + Message;
}
</script>
</head>

<body>
   <form id="form1" runat="server">
   <div>
    <input type="submit" value="Start Long Running Process" id="trigger" 
       onclick="BeginProcess(); return false;" style="width: 185px;"/>
    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
   </div>
   </form>
</body>

And LongRunningProcess.aspx.cs:

protected void Page_Load(object sender, EventArgs e)
{
   for (int i = 1; i <= 9; i++)
   {
       UpdateProgress(i * 10, " Completed.");
       System.Threading.Thread.Sleep(1000);
   }
   UpdateProgress(100, "Finished!");
}

protected void UpdateProgress(int PercentComplete, string Message)
{
    Response.Write(String.Format("<script type=\"text/javascript\">parent.UpdateProgress({0}, '{1}');</script>", PercentComplete, Message));
    Response.Flush();
}

You can see the result and also read more in Dave Ward's great article here: Easy incremental status updates for long requests.

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
3

It is rare but .NET can sometimes run asynchronous tasks synchronously (it's not clear from the documentation on MSDN when this might happen) but if this is happening in your case it will block the message loop in your WinForms application.

To test this theory you could try putting an Application.DoEvents() call in the ProgressChanged handler and the DoWork handler and see if that helps. It's an ugly work around but it should force the UI to update if the disptacher is running your tasks synchronously.

keith
  • 5,122
  • 3
  • 21
  • 50
2

You have essentially two options.

One, you can poll from the browser on a timer to get the current percent complete, using JavaScript. setInterval is the obvious method to use, and you could use jQuery or similar to do AJAX calls to your server. This is somewhat inefficient though, since your server sounds like it knows when it's making progress or done, so the server should raise events.

Two, which is more what you want, is to use SignalR. You've got things set up to "push" from the server as timing events are raised, but there's no simple way to do that within HTTP (HTML5 WebSockets are an alternative as well). Using a server-push technology like SignalR will let you create "hubs" that raise events to clients. They can be user-specific targeted events or all-clients types of events - up to you.

Check out the intros/demos here. They've made a fairly hard problem quite easy: http://www.asp.net/signalr

Also as mentioned by others, you probably don't want to use BackgroundWorker. Try QueueBackgroundWorkItem. http://blogs.msdn.com/b/webdev/archive/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-long-background-process-in-asp-net.aspx

Todd Sprang
  • 2,899
  • 2
  • 23
  • 40