views:

429

answers:

7

I have an ASP.NET page that is taking too long to load. A little testing shows that the server side logging is taking a fair chunk of time and (because the user never needs to see the logging results) I want to delay it until after the page has loaded.

Is there a simple way to do this?

I've tried placing it in the page's Disposed event but that doesn't seem to fire and in the Unload event but that fires too soon. I'd rather not have to spawn a thread but I might be able to if that's what it takes.

I am NOT looking for AJAX. I want to do a normal full page load and then after the page has loaded (as seen from the client side) do a little more processing.

+1  A: 

You are looking for an Asynchronous process. AJAX allows for this as well as other implementations. Do a search for Async and ASP.Net and you'll find a ton of resources.

Basically your web page kicks off and runs processes in a separate thread while the UI continues to render.

Jay
I known about AJAX and it's not what I'm looking for. As for ASP.NET+Async, I get tones of results for performing task asynchronously *while the pages is loading* rather than after.
BCS
See edit: The problem is server side, not client side.
BCS
So, why not let the page load fully then kick a ajax process off that calls your server to start logging or what ever other method that you want? AJAX is an Async process that can call any server based method.
Jay
For that to work, I'd either need to pass the logging data to the client (with all the security issues that implies) or figure out how to store it somewhere more than one page can get to it from. Both of those sound worse than my original problem.
BCS
one more suggestion, if you collect all your stuff into a single log object then you can stuff that object in the session variables for the user then make that AJAX call back to the server and write the session info out to log file/location and clear out the session variable. Not sure if your bottle neck is the actual writing of the log or the building of it.
Jay
+1  A: 

Try calling Flush on the response stream before you log. Unload isn't fired until after the entire response is sent. If you Flush() there and then log, it should be the last thing the page does.

The effect should be that the user sees the page, but that it isn't finished loading until the log is done. But they can interact with the page, so probably they won't care.

Lou Franco
This may not work on all browsers (depending on how they buffer) and/or keep making the browser status say something along the lines of "Loading..."
Spencer Ruport
Sounds like it might work. Can I safely do that from `Page_Load`? (/me going a Googleing for how to get the response stream)
BCS
Response.Flush sends the content to the client as it is rendered, be careful with this because if your logging is slowing down the process then the page will appear to load slowly to your clients as the logging for that section completes. Pieces at a time.
Jay
You can call it whenever you want, but if nothing has been written to the response, then it won't matter. It makes more sense later in the lifecycle. Browsers don't have to render, but they pretty much all do as much as they can --- as long as they get the closing tags and can tell how the page will look.
Lou Franco
+1  A: 

This is possible with asynchronous threads. We created a Page for a customer which checks every 2 minutes if there is an update and if so we updated the page.

Maybe this howto will help you:

http://www.eggheadcafe.com/articles/20060918.asp

hope could help you

OemerA
A: 

Instead of logging it into your log, make a string out of it (using StringBuilder) and towards the end, push that entire string into Log.

You could lose the logging, if the page fails to load due to exception.
Pardon me, if I have not understood the problem correctly.

shahkalpesh
As it happens, I already only do logging at the end...
BCS
I guess HttpModule could be of use. i.e. those that run after the request is complete. Not sure if it relates well to your case.
shahkalpesh
A: 

What kind of logging is it and where is it going?

One way may be to spin off another thread (you'd need to increase the amount of threads available to asp.net) and perform the logging in there. You could use the ParameterizedThreadStart and pass an object to be used for logging. (Don't pass a database connection/command object though, that'd be bad!)

Joshua
+8  A: 

This appears to work:

protected void Page_Unload(object sender, EventArgs e)
{
    HttpContext.Current.Response.Flush();
    HttpContext.Current.Response.Close();
    Thread.Sleep(20000); // Do processing here instead of sleeping :)
    Debug.WriteLine("Done!");
}

You mentioned the Unload event fires too soon, but it looks to me that it's right on time. You just need to close the connection manually. Flushing seems to be mandatory as well, which is a little strange, as I thought a flush was implicit when you close.

There might be some downsides to this, as it keeps the process handling the request busy, unable to handle the next HTTP request. IIS7 has a configurable limit on the number of simultaneous requests however. You wanted simple, I think this is as simple as it will get.

Thorarin
This seems to work just fine.
BCS
+3  A: 

Have you considered creating a logging service that takes a queue of messages to log and just performs the logging in its own thread?

Using this, you can leave all the logging to occur where they were in the code before and just make asynchronous calls to the logging methods.

Babak Naffas
A bit more complicated than Thorarin's solution, but still an option.
BCS
Or try a combination: Thorarin's solution + call the logging method on a separate thread so that your request can complete from IIS's point of view.
Babak Naffas