views:

1863

answers:

7

This is a multi-part question.

I have a process that can take several minutes to complete, it is ran by a calling a HTTPHandler using a asynchronous javascript request.

Question 1: How can I ensure that this request does not time out on both the server and the client?

Question 2: Is it possible to emit data from the HTTPHandler while processing that is sent back to the XmlHttpRequest object before the final page is completed?

I'd like to calculate actual workload and return percentage done. I'm guessing that this is possible.

Any tips?

EDIT:

A quick test:

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";
        for (int i = 0; i < 100; i++)
        {
            context.Response.Write("Hello World " + i + Environment.NewLine);
            System.Threading.Thread.Sleep(500);
            context.Response.Flush();
        }            
    }

Pushes Hello World bit by bit to the client...This works on a synchronious request, I'll see if a xmlHttpRequest gets a readystatechange event for each line.

I've always avoiding multithreading on ASP.NET apps because you don't have control of when the working process will die, which will result in all of its spawned threads dieing.

Instead, why re-invent a separate thread pool when IIS is already doing this for you.

A: 

What I've done in the past is start the long-running process on a new thread, and have a property on the process class which states the % complete. Then every so often, the browser can make an AJAX call to an HttpHandler that just polls that % complete property. That way the HttpHandler returns immediately.

There can be issues to consider if the job is important, such as mitigating for the worker process to recycle mid-job or saving the state of the job so it can be restarted. If the job is extremely critical, it's better to write a Windows Service that executes the job, and use Remoting or something to query the progress.

Rex M
A: 
  1. You can alter the request timeout value in web.config, somthing like: <configuration> <system.web><httpRuntime executionTimeout="1000" /></system.web></configuration>

  2. As far as I know there is no way to send information back down the same async request. Most Ajax UI's I've seen create that behavior by having a static class that holds the statistics for the running tasks, then polls that with another async request or iframe. A good example of something similar is the Neat Upload Control .

Element
A: 

Here's one idea...

If you have a process that takes "several minutes" to process, you might be best off creating a separate thread (or separate queue of threads) rather than using ASP.NET worker threads. This is because if you use up all the worker threads, then your web server could hang. For more information on this issue: http://msdn.microsoft.com/en-us/magazine/cc164128.aspx

Your first AJAX request would be to launch the process. Subsequent calls would be to get the status of the process including the % complete. Use a timer to poll (every few seconds or whatever seems to work best) to get the % complete until it's all done.

AJAX requests (XmlHttpRequest) don't have timeouts per-se on the client (http://luke.breuer.com/tutorial/xmlhttprequest.aspx... scroll down to timeouts), but I don't think it's a good idea to have them off for several minutes doing work if at all possible:

Keltex
Separate threads still live inside the worker process.
Rex M
A typo which I corrected.
Keltex
A: 

Download the source file from this website

http://www.stonebroom.com/dafiles/6744-code.zip

Check the url ~/loadpost/stagedloading.aspx.

Fahad
A: 

HTTP requests by definition are stateless. As others pointed out - you can not predict when IIS will recycle the process.

The better approach is to create a Windows service to do the real work, and the HTTPHandler, or page or whatever to query it about the progress and return this to the client. You can install the service on the same machine, and then use pipes or whatever remoting channel you want to connect between your page/handler to the service.

Sunny
A: 

For what its worth,

public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "text/plain";
    for (int i = 0; i < 100; i++)
    {
        context.Response.Write("Hello World " + i + Environment.NewLine);
        System.Threading.Thread.Sleep(500);
        context.Response.Flush();
    }            
}

And on the client side:

httpObject.onreadystatechange = function()
{
    // This is called whenever Flush() is called on the server.
    // when readyState = 4, everything is done, but I can check responseText at anytime.
}

Works just fine.

FlySwat
The app pool recycling won't affect this?
DaRKoN_
A: 

Check out the article written on blog aspdotnetmatters.blogspot.com also you can download demo code. LongRunning process are typical in huge web application but we can keep track of them and handle them very easily.

  1. Handling LongRunning Processes article --> LongRunningProcesses on Web
ashish