views:

172

answers:

2

Hello,

I have an ASP.NET page that I want to be able to generate and save. The page takes a really long time to load, so I'd like to do it in a separate thread, while using the session of the user who requested the page (so that the page looks like it would if they viewed it themselves).

Opening a new thread from code-behind breaks the Request object and Server.Execute, so I need another way of making this request that will allow the user to view other pages while the request is taking place.

Is there any way to do this?

Thanks!

+1  A: 

You can definitely do this by using a facade to the Request and Session data. It would require you to change all of the code in your page to use the facade instead of calling Request or Session directly, however.

When launching the separate thread, create a new (custom) SessionData object which stores all the info you need about Request and Session, and store it in a database or HttpRuntime.Cache. Pass the identifier for that object into your thread, so that thread knows which SessionData object to use.

If you are in your special worker thread, you can instantiate your SessionFacade with the ID. Otherwise, instantiate it with no parameters.

Here's an example of the SessionFacade, hopefully enough to get you started:

class SessionFacade
{
    private string _threadID;

    public SessionFacade() { }

    public SessionFacade(string threadID)
    {
        this._threadID = threadID;
    }

    public object this[string key]
    {
        get
        {
            return this.GetData(key);
        }
    }

    protected object GetData(string key)
    {
        if(!string.IsNullOrEmpty(this._threadID))
        {
            return ((SessionData)HttpRuntime.Cache[this._threadID])[key];
        }
        else
        {
            return Session[key];
        }
    }
}
Rex M
A: 

In our particular case, the problem was that every page we requested held a session lock. This made it impossible to visit more than one page at a time:

http://blogs.msdn.com/amitsh/archive/2007/08/01/why-i-cannot-execute-two-requests-from-the-same-session-simultaneously-for-an-asp-net-application.aspx

This is expected behavior. The reason behind this is session state implements a reader/writer locking mechanism:

  • A page (or frame) that has session state write access (e.g. <%@ Page EnableSessionState="True" %>) will by default hold a writer lock on the session until the request finishes.

  • A page (or frame) that has session state read access (e.g. <%@ Page EnableSessionState="ReadOnly" %>) will hold only a reader lock on the session until the request finishes.

  • As we can understand based on concepts of locks – a Reader lock will block a writer lock; a Reader lock will NOT block a reader lock; a Writer lock will block all reader and writer locks.

This lock is acquired within the event AcquireRequestState and released in the event ReleaseRequestState of a request. That's why if two frames/pages both have session state write access (the default option unless you use EnableSessionState="ReadOnly" ), one frame/page has to wait for the other to finish.

By setting EnableSessionState to ReadOnly, we could push a redirect (and thus request another page) while waiting for the first page to finish executing in the background.

Chris