views:

94

answers:

1

I have a demo using jQuery ajax to invoke web service,at the same time,another of a request shows the progress.

Why it not show progress immediately, while the last to show all the progress. The code like this: WebService.ashx(c#):

public class WebService : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string invoke = string.Empty;
        string jsoncallback = string.Empty;

        if (!string.IsNullOrEmpty(context.Request["invoke"]))
            invoke = context.Request["invoke"].ToString().Trim();
        if (!string.IsNullOrEmpty(context.Request["jsoncallback"]))
            jsoncallback = context.Request["jsoncallback"].ToString().Trim();

        context.Response.ContentType = "application/x-javascript; charset=utf-8";
        switch (invoke.ToLower())
        {
            case "call":
                int currentValue = 0;
                int TotalValue = 100;
                HttpContext.Current.Cache.Remove("progress");
                HttpContext.Current.Cache.Insert("progress", currentValue + "," + TotalValue, null, 
                    DateTime.Now.AddMinutes(60),System.Web.Caching.Cache.NoSlidingExpiration);

                for (int i = 1; i <= TotalValue; i++)
                {
                    currentValue = i;
                    //TODO...
                    HttpContext.Current.Cache.Insert("progress", currentValue + "," + TotalValue, null,
                        DateTime.Now.AddMinutes(60), System.Web.Caching.Cache.NoSlidingExpiration);
                    Thread.Sleep(100);
                }
                context.Response.Write(string.Format("{0}({{error:{1}, message:\"{2}\"}})", jsoncallback, false.ToString().ToLower(), "finished."));
                break;
            case "progress":
                string progress = "100,100";
                if(HttpContext.Current.Cache["progress"] != null)
                {
                    progress = HttpContext.Current.Cache["progress"].ToString();
                }
                context.Response.Write(string.Format("{0}({{error:{1}, message:\"{2}\"}})", jsoncallback, false.ToString().ToLower(), progress));
                break;
            default:
                context.Response.Write(string.Format("{0}({{error:{1}, message:\"{2}\"}})", jsoncallback, false.ToString().ToLower(), "parameter error."));
                break;
        }
    }

    public bool IsReusable
    {
        get{return false;}
    }
}

and the page:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
 <head>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 <style>
    .ProgressBar {
        position:relative;
        margin-top:30px; 
        margin-bottom:20px;
        margin-left:240px;
        width: 220px;
        border: 1px solid #B1B1B1;
        overflow: hidden;
    }
    .ProgressBar div {
        position:relative;
        background: #2BD029;
        color: #333333;
        height: 15px;
        line-height: 15px;
        text-align:left;
    }
    .ProgressBar div span {
        position:absolute;
        width: 220px; 
        text-align: center;
        font-weight: bold;
    }
 </style>
 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"&gt;&lt;/script&gt;
 <script type="text/javascript">
    var intervalID;

    function RequestProcess(){
        $.getJSON("http://localhost:4397/webservice.ashx?invoke=progress&amp;jsoncallback=?", function(data) {
            var progress = data.message;
            var position = parseInt(progress.split(",")[0] / progress.split(",")[1] * 100);        
            if(isNaN(position))
                position = 0;
            $('#divMessage').append("<br/>"+position);
            if (position >= 100) stopRequestProcess();
            $('.ProgressBar > div').css({ "width": position + "%" });
            $('.ProgressBar > div > span').html(position + "%");
            $('#ProgressInfo').html(position >= 100 ? "finished" : position);
        });
    }
    function stopRequestProcess(){
        clearInterval(intervalID);
    }

    $(document).ready(function(){
        $('#btnStart').click(function(){
            $('#divMessage').html('');
            $.ajax({
                type: "GET",
                url: "http://localhost:4397/webservice.ashx?invoke=call&amp;jsoncallback=?",
                dataType: "jsonp",
                async: false,
                error: function(xhr, ajaxOptions, thrownError) {
                    stopRequestProcess();
                },
                success: function(response) {
                    stopRequestProcess();
                    $('.ProgressBar > div').css({ "width": "100%" });
                    $('.ProgressBar > div > span').html("100%");
                    $('#ProgressInfo').html("finished");
                }
            });

            intervalID = setInterval(RequestProcess, 500); 
        });
    });
 </script>
 </head>

 <body>
        <div>
            <div>
                <div class="ProgressBar" style="*margin-left:0px"  align="left">
                    <div style="width:0%;*margin-left:0px"><span>0%</span></div>
                </div>
                <div id="ProgressInfo" class="ProgressInfo">processing...</div>
            </div>
            <button id="btnStart" name="btnStart">start</button>
        </div>
        <br/>Progress Information:<br/>
        <div id="divMessage"></div>
 </body>
</html>
A: 

Couple of remarks about your code:

  1. You need to start a new thread to perform the lengthy operation and return immediately and not block the worker thread
  2. You are using the cache to track progress, which is not reliable. ASP.NET can evict the cache under different circumstances like for example running low on memory, etc...

Here's an example I've put:

public class WebService : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "application/x-javascript";
        var id = context.Request["id"];

        if (string.IsNullOrEmpty(id))
        {
            id = Guid.NewGuid().ToString();
            context.Application[id] = 0;
            new Thread(() =>
            {
                for (int progress = 0; progress < 100; progress++)
                {
                    context.Application[id] = progress;
                    Thread.Sleep(100);
                }
                context.Application.Remove(id);
            }).Start();
        }

        var serializer = new JavaScriptSerializer();
        context.Response.Write(serializer.Serialize(new
        {
            id = id,
            error = false,
            progress = context.Application[id] ?? 100
        }));
    }

    public bool IsReusable
    {
        get { return false; }
    }
}

And the client:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>Test</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"&gt;&lt;/script&gt;
<script type="text/javascript">
    var intervalId = null;
    $(function () {
        $('button').click(function () {
            $(this).attr('disabled', 'disabled').text('processing...');
            $.getJSON('/webservice.ashx', function (result) {
                intervalId = setInterval(function () {
                    poll(result.id);
                }, 1000);
            });

        });
    });

    function poll(taskId) {
        $.getJSON('/webservice.ashx', { id: taskId }, function (result) {
            if (result.progress >= 100) {
                clearInterval(intervalId);
                $('button').removeAttr('disabled').text('start');
            }
            $('#progress').html(result.progress + '%');
        });
    }
</script>
</head>
<body>
    <button>start</button>
    <div id="progress"></div>
 </body>
</html>
Darin Dimitrov
hi, Darin Dimitrov, I tested your code had some trouble, and i modified some code support jsonp, it work well, thank you very much!code: string jsoncallback = string.Empty; if (!string.IsNullOrEmpty(context.Request["jsoncallback"])) jsoncallback = context.Request["jsoncallback"].ToString().Trim();//.... context.Response.Write(jsoncallback + "(" + serializer.Serialize(new { id = id, error = false, progress = context.Application[id] ?? 100 }) + ")");
'/webservice.ashx' -> '/webservice.ashx?jsoncallback=?'