views:

248

answers:

3

I am fixing an ASP.NET application that makes heavy use of session to track per-page data. One of the problems is that the session bleeds between pages.

ViewState would be a better solution, except:

  • The data is not serializable
  • There is too much data to be sending back and forth each postback

So I want to:

  • create a page key for the session data (i.e. stick a random GUID in a hidden field)
  • expire data from an abandoned page even if the overall session is active

Is there a good way to expire partial session data?

+2  A: 

The following temporary storage locations are available:

  1. Session. This follows a user around and uses a cookie. It can be configured to use a URL param to retrieve. Session can also be configured to be stored in process(inproc) on the web server, in SQL Server, or in a state server. InProc can store any data type, but the others require the type to be serializable.
  2. Cache. Data stored in Cache is available to be used by any user in an session. It works similar to session, as the objects are retrievable via a key. One of the nicer features of cache is that you can control how long things are stored, and you can consume event when they expire. You can store anything here, but you may run into issues with using it in a webfarm.
  3. HttpContext. This is scoped to the current request. Remember, requests can be webservice calls, calls to get webpages to get HTML, or calls to a service that returns images. Anything can be stored here.
  4. ViewState. View state is scoped to a page. Must be serializable.

You may want to examine cache. If you're using a webfarm, it won't work, but you could use a GUID of some sort as the key that you map back to a session.

Darthg8r
Cache may be a possibility if I can guarantee it will be around as long as the 20 minutes or so that a session would last.
Korey
Here is the Cache code I used:Cache.Insert(key, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(0, 20, 0), System.Web.Caching.CacheItemPriority.NotRemovable, null);
Korey
CacheItemPriority.NotRemovable prevents the Cache from removing the data due to memory pressure.
Korey
A: 

Perhaps on each page !IsPostBack or through a base page you could null out all references to session data not pertaining to that page. This would "expire" the data each time the user goes to another page in the site.

If the user leaves the site or goes in-active, there's not much you can do until the session expires, but in this scenario there would only be one page worth of session data per user.

Kurt Schindler
I do want to allow multiple pages to be viewed (same page, but with different request data). I don't want one page automatically destroying the session data for another, I just want it to be able to expire.
Korey
+1  A: 

I would probably do it this way:

  1. Create an object to store the state information you want to be page specific. If different pages need different information, create multiple classes.
  2. Store this object in a single session key: Session["PageSpecific"]; for example.
  3. Create a class which inherits from System.Web.UI.Page.
  4. In the OnLoad event of the base class, clear the session key if the the page is not performing a postback.
  5. Create and call an overloadable method to populate the session object.
  6. Instead of inheriting from System.Web.UI.Page in each of your pages, inherit from your new base class.

Something like this (warning: air code. May contain syntax errors):

public class PageBase
    : System.Web.UI.Page
{
    protected overrides OnInit(System.EventArgs e) {
        base.OnInit(e);

        if(!this.IsPostBack) {
            Guid requestToken = System.Guid.NewGuid();
            ViewState["RequestToken"] = requestToken;

            Session["PageSpecific" & requestToken.ToString()] = InitializePageSpecificState();
        }
    }

    protected virtual object InitializePageSpecificState() {
        return new GenericPageState();
    }

    //You can use generics to strongly type this, if you want to.
    protected object PageSpecificState {
        get {
            return Session["PageSpecific" & ViewState["RequestToken"].ToString()];
        }
    }
}
AaronSieb
This has the same problem as the previous answer. My question may not have been clear enough.Some user may be viewing Default.aspx in multiple tabs, with different request data (or even the same). I want each to have its own server side storage space.
Korey
AaronSieb
@Korey The main difficulty with allowing for multiple tabs to be open is that you can't clean up the Session from a request until the overall Session has expired... This may or may not be an issue depending on the size of your user base.
AaronSieb
Answer updated based on Korey's comment.
AaronSieb