We will start with ASP.NET MVC sample. First thing to do is adding some JavaScript and CSS references:
<link href="<%= Url.Content("~/Content/jquery-ui-1.8.2.css") %>" rel="stylesheet" type="text/css" />
<script src="<%= Url.Content("~/Scripts/jquery-1.4.2.min.js") %>" type="text/javascript"></script>
<script src="<%= Url.Content("~/Scripts/jquery-ui-1.8.2.min.js") %>" type="text/javascript"></script>Markup for Progressbar is very simple (just one div), so we will need only two lines of HTML in this sample:<button id="operation">Operation</button>Now some interesting stuff begins. We need two controller actions. One for triggering actual process and one for reporting progress:
<div id="progressbar" style="width:500px"></div>
/// <summary>What is missing is JavaScript, which will initialize Progressbar, trigger the operation and set timer for updating progress:
/// Action for triggering long running operation
/// </summary>
/// <returns></returns>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Operation()
{
HttpSessionStateBase session = Session;
//Separate thread for long running operation
ThreadPool.QueueUserWorkItem(delegate
{
int operationProgress;
for (operationProgress = 0; operationProgress <= 100; operationProgress = operationProgress + 2)
{
session["OPERATION_PROGRESS"] = operationProgress;
Thread.Sleep(1000);
}
});
return Json(new { progress = 0 });
}
/// <summary>
/// Action for reporting operation progress
/// </summary>
/// <returns></returns>
[NoCache]
public ActionResult OperationProgress()
{
int operationProgress = 0;
if (Session["OPERATION_PROGRESS"] != null)
operationProgress = (int)Session["OPERATION_PROGRESS"];
return Json(new { progress = operationProgress }, JsonRequestBehavior.AllowGet);
}
<script type="text/javascript">The result looks like this:To make it work in ASP.NET WebForms, we need two PageMethods instead of actions:
$(document).ready(function () {
//Progressbar initialization
$("#progressbar").progressbar({ value: 0 });
//Button click event
$("#operation").click(function (e) {
//Disabling button
$("#operation").attr('disabled', 'disabled');
//Making sure that progress indicate 0
$("#progressbar").progressbar('value', 0);
//Perform POST for triggering long running operation
$.post('<%: Url.Action("Operation") %>', function (data) {
//Updating progress
$("#progressbar").progressbar('value', data.progress);
//Setting the timer
window.progressIntervalId = window.setInterval(function () {
//Getting current operation progress
$.get('<%: Url.Action("OperationProgress") %>', function (data) {
//Updating progress
$("#progressbar").progressbar('value', data.progress);
//If operation is complete
if (data.progress == 100) {
//Clear timer
window.clearInterval(window.progressIntervalId);
//Enable button
$("#operation").attr('disabled', '');
}
});
}, 500);
});
});
});
</script>
/// <summary>and modified JavaScript:
/// PageMethod for triggering long running operation
/// </summary>
/// <returns></returns>
[System.Web.Services.WebMethod(EnableSession=true)]
public static object Operation()
{
HttpSessionState session = HttpContext.Current.Session;
//Separate thread for long running operation
ThreadPool.QueueUserWorkItem(delegate
{
int operationProgress;
for (operationProgress = 0; operationProgress <= 100; operationProgress = operationProgress + 2)
{
session["OPERATION_PROGRESS"] = operationProgress;
Thread.Sleep(1000);
}
});
return new { progress = 0 };
}
/// <summary>
/// PageMethod for reporting progress
/// </summary>
/// <returns></returns>
[System.Web.Services.WebMethod(EnableSession = true)]
public static object OperationProgress()
{
int operationProgress = 0;
if (HttpContext.Current.Session["OPERATION_PROGRESS"] != null)
operationProgress = (int)HttpContext.Current.Session["OPERATION_PROGRESS"];
return new { progress = operationProgress };
}
<script type="text/javascript">The effect is pretty much the same:The samples for ASP.NET MVC and ASP.NET WebForms can be downloaded here. Enjoy.
$(document).ready(function () {
//Progressbar initialization
$("#progressbar").progressbar({ value: 0 });
//Button click event
$("#operation").click(function (e) {
//Disabling button
$("#operation").attr('disabled', 'disabled');
//Making sure that progress indicate 0
$("#progressbar").progressbar('value', 0);
//Call PageMethod which triggers long running operation
PageMethods.Operation(function(result) {
if (result) {
//Updating progress
$("#progressbar").progressbar('value', result.progress)
//Setting the timer
window.progressIntervalId = window.setInterval(function () {
//Calling PageMethod for current progress
PageMethods.OperationProgress(function (result) {
//Updating progress
$("#progressbar").progressbar('value', result.progress)
//If operation is complete
if (result.progress == 100) {
//Clear timer
window.clearInterval(window.progressIntervalId);
//Enable button
$("#operation").attr('disabled', '');
}
});
}, 500);
}
});
});
});
</script>


Email
18 comments:
Great article… just what I needed. Can you provide the download in a zip file?
Sure, I'll upload it to Codeplex on weekend.
Its available here: http://tpeczek.codeplex.com/releases/view/52932
Tomasz, I downloaded the MVC version and compiled and ran it. It compiles OK and starts up OK. I click the button and it initiates, but the bar never gets updated. I set breakpoints in the source code and Operation was called, but OperationProgress never got called. Sometimes when I run it, OperationProgress gets called a few times and then hangs. The Webforms version works consistently. Thanks. R. Tanenbaum
Hi Robert,
I will look into this tomorrow and let you know.
Greetings
Hi Robert,
The bug was caused by caching. I have updated the sample with fix (and some other things), you can download it form my SVN repository at CodePlex - https://tpeczek.svn.codeplex.com/svn/trunk/MVC/jQuery%20UI%20Progressbar%20Example/. The Lib.Web.Mvc which is referenced by the sample can be found at the same repository - https://tpeczek.svn.codeplex.com/svn/trunk/MVC/Lib.Web.Mvc/v3.0.0.0/Lib.Web.Mvc/
Greetings
Thank you. Your clue helped me solve it. I have not upgraded to MVC3 so I don't have the [NoCache] attribute. Instead I used the attribute
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
on the OperationProgress method. It is available in MVC2 and worked fine.
Thank you again.
NoCacheAttribute is not from ASP.NET MVC 3, is from my Lib.Web.Mvc project. You can grab the source code and use it in your project --> https://tpeczek.svn.codeplex.com/svn/trunk/MVC/Lib.Web.Mvc/v3.0.0.0/Lib.Web.Mvc/NoCacheAttribute.cs
Hi,
I used your web form version and while it does work right away, I noticed that each time after the progress bar increments it "flashes" or "refreshes" and the progress indicator is reset to 0 before being incremented again.
I'll check on this.
Hi, were you able to make any progress on this?
Honestly I can't recreate the problem with current repository/download version.
Is that possible to keep track of it after i have closed the browser? I mean, if the progress has not yet completed (eg:52%), i close the browser and i open it again, is that possible to see the progress? (maybe on 52..53..54%)
I guess the session will lose, we can't keep track. Is that a way to keep track after i have close the browser and resume..?
Great Article! Thks!
This is simple and great!
Hi
I'm tring to use the WabForm example but the progress counter is returning always 0. It seems that there is a probelm with the session param.
do u have any clue?
thanks
I can't reproduce such an issue, are you sure you are using latest repository version and you haven't done any modifications?
hi.
How i can using with file upload ?? (html4 over iframe). Now im using chunks uploading files over handler (webforms). Thanks.
Post a Comment