I am trying to put a web interface on a lengthy server side process which should send regular progress\statistic reports to the client as the process is running. How can I do this?
Here is what I have attempted so far. The session in the webmethod is null for as long as the loop is processing. Once the loop is finished and you press the start button again, it is able to pick up the session value and populate the label. How do I get this to send updates to the client while the process is running?
I am using VS2012 and ASP.NET 4.5.
EDIT: To be more specific, the problem occurs while the server is busy with the loop. If I take the loop away and simply try to pull a variable value from the server at regular intervals then there is no problem. Put that variable in a loop and try and fetch it at regular intervals and you’ll see what the problem is, the code I have posted should clarify the issue if you run it.
Thanks.
Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ClientProgressTest.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
function GetCount() {
$.ajax({
type: "POST",
url: "Default.aspx/GetCount",
contentType: "application/json; charset=utf-8",
data: {},
dataType: "json",
success: function (data) {
lblCount.innerHTML = data.d;
},
error: function (result) {
alert(result.status + ' ' + result.statusText);
}
});
setTimeout(GetCount, 5000);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<label id="lblCount"></label>
<br />
<br />
<asp:Button ID="btnGetCount" runat="server" Text="Get Count" OnClientClick="GetCount();" OnClick="btnGetCount_Click" />
</div>
</form>
</body>
</html>
Default.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ClientProgressTest
{
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
[WebMethod(EnableSession = true)]
public static string GetCount()
{
string count = null;
if (HttpContext.Current.Session["count"] != null)
{
count = HttpContext.Current.Session["count"].ToString();
}
return count;
}
protected void btnGetCount_Click(object sender, EventArgs e)
{
Session["count"] = null;
for (int i = 0; i < 10000000; i++)
{
Session["count"] = i;
}
}
}
}
I put a lengthy answer to this question here : How to update a status label inside ajax request
For the sake of others being able to find the same solution i’ll paste the answer here too:
==================================================================================
This example is using JQuery for the AJAX and the code-behind is in vb.net.
Essentially what you need to do is make your first call to begin the long process, then make a second call, repeatedly, using a second method to get the status of the long one.
AJAX
This is your main call to the long process. If needed, you will need to pass in the data to the method. Notice there is a processName. This should be a random string of sorts to ensure that you get the status of this process only. Other users will have a different random processName so you don’t get confused status.
JAVASCRIPT
Your second AJAX call will be to another method to get the progress. This will be called every XXX time by a timer method.
This is the TimerPoll function; which will fire every 3 seconds in this case
JAVASCRIPT
And finally, the GetProgress() function to, well, get the progress. We have to pass in the same processName used above, to get the process of this users call only
JAVASCRIPT
Now, in the back-end, you will have a couple of web methods that your AJAX communicates with. You will also need a shared/static object to hold all of the progress information, along with anything you want to pass back to the user.
In my case, i created a class which has its properties filled and passed back with every call to MyMainWorkerProcess. This looks a little like this.
VB.NET
I also have a shared property using this class, which looks like… ( this shared property is capable of holding multiple process progresses by multiple users – hence the dictionary. the key of the dictionary will be the process name. All progress data will be in the class ProcessData
My main worker function looks a little like this. Notice that we first make sure there isn’t another processProgress with the same
VB.NET
now all that is left is to call the progress method..All this is going to do is return the dictionary processData that has the same processName we set up earlier..
VB.NET
And voila..
So to recap..
don’t shoot me if there are a few typos 🙂