Web Progress Bar in c#
Solution 1
I used the Idea of @Mike.. and altered it a bit because the HttpContext.Current is null... and replaced it with an static object. this worked good for me also made some concurrency test and worked fine ..
<div style="width: 800px" class="css_container">
<cc1:ToolkitScriptManager ID="sm" runat="server" EnableScriptGlobalization="true"
EnableScriptLocalization="true" AsyncPostBackTimeout="60000" EnablePageMethods="true">
</cc1:ToolkitScriptManager>
<asp:UpdatePanel ID="upPanel" runat="server">
<ContentTemplate>
<asp:HiddenField ID="correlationKey" runat="server" />
<asp:Button ID="btn" runat="server" Text="Do Something"
CausesValidation="False" OnClick="btn_Click" OnClientClick="javascript:GetProgress();" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
function GetProgress() {
PageMethods.GetProcessed(document.getElementById("correlationKey").value,
function(result) {
alert(result);
if (result < 100) {
setTimeout(function(){GetProgress();}, 1000);
}
});
}
protected void btn_Click(object sender, EventArgs e)
{
// NEW CODE
// set the hidden field value here with a correlation key
var correlationKey = Guid.NewGuid().ToString();
this.correlationKey.Value = correlationKey;
AClass oClass = new AClass();
Thread oThread = new Thread(delegate()
{
oClass.UpdateSession(correlationKey);
});
oThread.Start();
}
public class AClass
{
public static Dictionary<string, int> ProcessedQueue { get; set; }
public void UpdateSession(string correlationKey)
{
var dictionary = ProcessedQueue; // HttpContext.Current.Application["ProcessedQueue"] as Dictionary<string, int>;
if (dictionary == null)
{
dictionary = new Dictionary<string, int>();
ProcessedQueue = dictionary;// HttpContext.Current.Application["ProcessedQueue"] = dictionary;
}
if (!dictionary.ContainsKey(correlationKey)) { dictionary.Add(correlationKey, 0); }
for (int i = 0; i < 100; i++)
{
dictionary[correlationKey] = i;
System.Threading.Thread.Sleep(1000);
}
}
}
[WebMethod(EnableSession = true), ScriptMethod]
public static string GetProcessed(string correlationKey)
{
var dictionary = AClass.ProcessedQueue; // HttpContext.Current.Application["ProcessedQueue"] as Dictionary<string, int>;
if (dictionary == null || !dictionary.ContainsKey(correlationKey)) { return "0"; }
return dictionary[correlationKey].ToString();
}
Solution 2
I think there might be a few things going on here:
-
Your thread might be terminating at the end of the response. I think you can fix that by changing the way you define your thread:
Thread oThread = new Thread(new ThreadStart(oClass.UpdateSession)); oThread.IsBackground = true; // Set this oThread.Start();
-
You're returning a string percent to your callback function, and then comparing it against a number. It's not really an issue, but for the sake of good programming, you should change your server-side
GetProcessed()
to return an actual integer:public static int GetProcessed() { int result = 0; int.TryParse(HttpContext.Current.Session["processed"].ToString()), out result); return result; }
-
UpdatePanel requests initiate a full page lifecycle behind the scenes. Can you verify that this code isn't resetting your progress every tick of your GetProcessed() web method?
if (!IsPostBack) { Session["processed"] = 0; }
Solution 3
The issue is that you are calling in on a different Session
than the one the value is being updated on. So, you have a couple of options.
First you could make that an Application
variable if your application is only used by one user (very unlikely but I don't know anything about the app).
Second, you can use some sort of correlation key so that you can get the value from an Application
variable that is keyed.
Make a change in the button click:
protected void btn_Click(object sender, EventArgs e)
{
// NEW CODE
// set the hidden field value here with a correlation key
var correlationKey = Guid.NewGuid().ToString();
this.correlationKey.Value = correlationKey;
AClass oClass = new AClass();
Thread oThread = new Thread(delegate()
{
oClass.UpdateSession(correlationKey);
});
oThread.Start();
}
Now modify the JavaScript like this:
function GetProgress() {
PageMethods.GetProcessed(document.getElementById("correlationKey").value,
function(result) {
alert(result);
if (result < 100) {
setTimeout(function(){GetProgress();}, 1000);
}
});
}
Now modify the GetProcessed
method like this:
[WebMethod(EnableSession=true), ScriptMethod]
public static string GetProcessed(string correlationKey)
{
var dictionary = Application["ProcessedQueue"] as Dictionary<string, int>;
if (dictionary == null || !dictionary.ContainsKey(correlationKey)) { return "0"; }
return dictionary[correlationKey].ToString();
}
Now modify the UpdateSession
method like this:
public void UpdateSession(string correlationKey)
{
var dictionary = Application["ProcessedQueue"] as Dictionary<string, int>;
if (dictionary == null)
{
dictionary = new Dictionary<string, int>();
Application["ProcessedQueue"] = dictionary;
}
if (!dictionary.ContainsKey(correlationKey)) { dictionary.Add(correlationKey, 0); }
for (int i = 0; i< 100; i++)
{
dictionary[correlationKey] = i;
System.Threading.Thread.Sleep(1000);
}
}
And now clean out the Page_Load
.
Solution 4
Maybe I missed something, but your javascript (at least what you put in the question), isn't updating anything on the page. You said you have 0 in the progress bar all the time, which could be because you commented out the line that changes the display.
//document.getElementById("divProgress").innerHTML = result + "%";
Is the alert
showing the correct value? Also, have you confirmed that UpdateSession()
is running correctly and actually setting a value in the session?
Related videos on Youtube
Hector Sanchez
Updated on June 04, 2022Comments
-
Hector Sanchez almost 2 years
I'm looking for a way to display a "progress bar" in web using webforms with c#.
I made a quick example, I just want a label to show like 1%, 2%, 3% etc.. about a background process that will be running in the server. And when it finish update something like showing an alert or something, The real need is a little more complicated than that but getting the bases I think I can make it by my own. The problem that I having with the code is that I'm always getting 0.. in my "progress bar" it doesn't get updated, I'm missing something but I don't know what it is.
Edit
I tried to alert the value every second to see the value instead of the label, but it is not working anyway.
I missed the
OnClientClick="javascript:GetProgress();"
in the first queston, i Updated it, it is not working anywayEdit 2
HttpConext.Current is being null when calling it as a thread.. Should I use something more than a session or application, perhaps a singletone class?
Any Help would be really appreciated.
Importanth thigs from The ASPX and JS
<div style="width: 800px" class="css_container"> <cc1:ToolkitScriptManager ID="sm" runat="server" EnableScriptGlobalization="true" EnableScriptLocalization="true" AsyncPostBackTimeout="60000" EnablePageMethods="true"> </cc1:ToolkitScriptManager> <asp:UpdatePanel ID="upPanel" runat="server"> <ContentTemplate> <asp:Button ID="btn" runat="server" Text="Do Something" CausesValidation="False" OnClick="btn_Click" OnClientClick="javascript:GetProgress();" /> </ContentTemplate> </asp:UpdatePanel> </div>
function GetProgress() { PageMethods.GetProcessed(function(result) { alert(result); if (result < 100) { setTimeout(function(){GetProgress();}, 1000); } }); }
Important Things from Code Behind
[WebMethod(EnableSession=true), ScriptMethod] public static string GetProcessed() { return HttpContext.Current.Session["processed"].ToString(); } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Session["processed"] = 0; } } protected void btn_Click(object sender, EventArgs e) { AClass oClass = new AClass(); Thread oThread = new Thread(delegate() { oClass.UpdateSession(); }); oThread.Start(); }
Important Things from the Aclass
public class AClass { public void UpdateSession() { for(int i = 0; i< 100; i++) { HttpContext.Current.Session["processed"] = i; System.Threading.Thread.Sleep(1000); } } }
-
Mike Perrenoud over 11 yearsWould it be because this line
//document.getElementById("divProgress").innerHTML = result + "%";
is commented out?
-
-
Gromer over 11 yearsCan you verify
UpdateSession()
is running? -
Gromer over 11 yearsAlso, is your
GetProgress()
in your javascript running off the timer as it should be since the value is < 100? I'm assuming that you're getting an alert every second with 0 in it? -
Hector Sanchez over 11 yearsright, the alert shows itself every second with the value of 0