views:

167

answers:

1

When a user clicks a button, I use the ThreadPool.QueueUserWorkItem to spawn a thread that kicks off a long running process. I would like to make a button visible when the thread is completed so that user can click on it.

Is there a completed event in ThreadPool

What am I trying to do?

One of the pages has a button when clicked connects to a WS and kicks off a long running process that creates a file. During the processing time, I would like to show a progress bar to the user. Once the processing is completed, I would like to provide a link to the file that was created. Many users will be clicking on the button the same time that creates different files. I guess you would call this a single request that can be implemented using the Async approach?

Quick Qs about Async pages:

  1. The MSDN link has the following code:

    AddOnPreRenderCompleteAsync ( new BeginEventHandler(MyBeginMethod), new EndEventHandler (MyEndMethod) );

It appears that the MyBeginMethod is kicked off on Page Load, will the same code snippet work for me if i want to initiate the async process on a button click?

  1. Can I access the UI controls in MyBeginMethod and MyEndMethod methods (so that I can make a download file button visible on the process completion? Or does a different thread own these controls?
+4  A: 

Nope.

You'll have to store the fact you've completed somewhere available to your ASP.NET pages and the method doing your work, like the HttpCache.

If this is all happening within a single request, skip the thread pool and check out asynchronous pages.


First, if the file is created per user, then the result of the long running action should be stored in the Session, not the cache. The cache is shared between users, and the session is per-user.

The long running task can create the file, then store the file path in the session for that user. Whenever the user sends another request for the file, the session is checked for this file.

There are a few options for the UI during this. One is by postbacks to the server, the other is ajax calls.

Ajax may not be the easiest, even though there are plenty of frameworks (like jQuery) and lots of information on the net about how to make an asynchronous postback. If the process is very long, users might browse away, etc, making your task harder to implement.

Another option is to make your request for the file, then redirect to a holding page. This holding page has a script that automatically refreshes every X seconds. It displays to the user a notification such as "Please wait, creating your file." Every time this page posts back to the server the existence of the file is checked. If its not ready yet, then you return to the holding page. Eventually, the file becomes ready and you can redirect the user to another page where the file is downloaded/displayed/whatever.

The second option is probably easier and more straightforward for you to implement. Here's the pseudocode:

  1. User clicks a link to get the file
  2. On postback, server redirects to the holding page
  3. User's browser is redirected to the holding page
  4. Request is handled by the holding page. The Session is checked for the file.
    1. If the session reports the file has not been, and is not being created, the file creation process is started. The holding page is returned to the user.
    2. If the session reports the file is being created, the holding page is returned to the user.
    3. If the session reports the file is made, the user is redirected to the download page
  5. The holding page has a javascript method that runs on load that reloads the page every X seconds.
Will
What about the BackgroundWorker class? Is that recommended?
That's used for desktop apps. The multithreading pattern designed for asp.net is the asynchronous pages pattern.
Will
Unfortunately, I cannot use the async pages as it's not happening within the single request.
Then go ahead and run your work in a ThreadPool thread and use the cache as a thread-safe (yep, it is thread safe) place to store the results of your work. Just check it on each request to see if your work is complete. http://msdn.microsoft.com/en-us/library/system.web.httpruntime.cache.aspx
Will
If I add a flag to the Cache object, when would I check for this flag in the ASP.NET page? Do I have to put it within a infinite while loop, something like this: while(true) { if (Cache["completed"] == true) break; }
Your question is strange. Why would you need to do this if this isn't happening in the span of a single request? Do you need to block until the data is there? If so, that is a single request. Otherwise, on every request where you need that data, check for it and act accordingly if it isn't there ("check back in a minute!") or if it is there ("Here's your report!"). If you're still confused, maybe you should update your question with details about **what** you are doing, not just **how** you're trying to do it. If you do this, leave me a comment so I'll know.
Will
@Will - I have edited my question with more details. Thanks