I'm trying to add a realtime progress report to my c#/asp.net 4.0 application for a slow loading page. I've look at the UpdatePanel and UpdateProgress Ajax controls but I don't think they're suitable.
Basically when the user click a button the page executes a number of tasks, I'd like the user to see an update as each one completes, instead of a report when they all complete and the page load completes.
The order thing would happen would be:
1. user click button to start
2. call method 1
3. when method 1 completes, user see "Method 1 done"
3. call method 2
etc.
Can anyone help with this?
This sort of asynchronous execution can be difficult to implement. A few solutions off the top of my head:
Totally asynchronous without AJAX:
- Use hits button, submits page.
Server generates a GUID for the task, and creates a record in your database. This might include:
- Guid (ID)
- Status flag/enum
- start time.
Server spawns a thread to handle the task and passes in the Guid.
- Server returns the GUID, along with a "Working..." message
- After n seconds/milliseconds/insert-time-span-here, browser posts the page again, including a "GetStatus" command and the GUID.
- Server checks the status flag in the database based on the GUID.
- Server returns a status message based on the DB record ("Step 2...", "Still working", or whatever is appropriate)
- Loop to step (5) until the status returned from the server indicates that the process is complete.
In the thread created in step (3):
- Thread start
- Read current status from the DB record
- Execute the next step based on that status
- Update the DB status to indicate that it's ready to do the next step, or set an error flag.
- Sleep for a few milliseconds to keep from blocking the app (might be unnecessary - I'm not sure how threads interact under IIS)
- Loop to (2) until everything's done.
- Thread exits.
Here's an example of easily creating a thread with a lambda.
(new Thread(
() => {
DoLongRunningWork();
}
) { Name = "Long Running Work Thread"
,
Priority = ThreadPriority.BelowNormal
}).Start();
Synchronous
Easier, but might cause some performance problems:
- User submits "Start" form.
- Server writes "Starting..." to the response stream and flushes the stream. This should get the text back to the client, I think, but I haven't tried it in years.
- Server executes first step.
- Server writes status to the response stream and flushes.
- Loop to step (3) until complete.
Effectively, the page keeps the connection open until the task is complete, and flushing the output periodically keeps the client from timing out. This may have problems with timeouts, etc, and your server configuration (output buffering, etc) might be an issue.
Background Task
Similar to the first asynchronous approach:
- User clicks "start"
- Server adds a row to the DB that identifies the task to be executed, retrieves the ID, and returns it to the client.
- Create a scheduled task (script, windows service, etc) that polls the table, executes the desired tasks and updates the status as it progresses.
- Client re-posts the form with the DB ID periodically. Server checks the ID against the DB and returns a message about the status (may include info about previous steps such as exec time, ETA, etc)
- Client Loops to (4) until the task is complete or errors out.
The difference between this and the first approach is that the thread lives in a separate process instead of IIS.
Each approach has its issues, of course, and there may be a simpler way to do this.