Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Session, Cookie, Query String & Cache Variables Unified

0.00/5 (No votes)
1 Dec 2009 5  
A wrapper to work with the session, cookie, query string or cache in a unified, flexible and type safe manner while offering full support for JSON serialization.

Introduction

Session, cookies, query string or cache? This is a question I often ask myself as a web developer and quite a few times over the years, I've found myself taking the wrong decision as my web projects grew more complex. I found the data persistence objects available in .NET 3.5 quite clunky and hard to maintain as they excluded strong typing and generics. Moreover each storage type had its own syntax, limitations and quirks adding quite a burden on their interoperability. Since I found nothing on the web to help me address those issues on a general scale, I started this project and decided to share it here.

Basically it provides you with a simple and unified model to work with, a strongly typed and generic wrapper that supports complex data types, via Json serialization, and a more maintainable approach to complex scenarios. Well to put it simply I might say that it is to the local storage models what the Entity Framework is to plain SQL, without the fancy interfaces.

Cookies and query strings can now be addressed much like the session object whereby data size remains the only significant limitation. Several storage types can be handled in one go and, for added security, query strings and cookies can be made tamper proof using machineKey based encryption. To address the data size issue, compression ability is supported. Note that primitive types are not serialized for optimization and compatibility with external objects like the ASP.NET datasources.

Working with the variables in a disconnected manner is now possible thus eliminating any unnecessary overhead when several manipulations need to be made. A new text based storage system has been introduced to deal with the limitations and security issues associated with the conventional cookie model. It works much like the conventional cookie except that it is stored on the server and therefore cannot be accessed from the client side. It also has no size limit and so it is up to you to use it responsibly.

Another cool feature is the UIPersistence class. Using one line of code, you can persist any property value within a control by storing it in storage type of your choice. An example of its usage is demonstrated in Example 3 within the demo. Please have a look at it for more information.

Using the Code

To start, with let us create an object to store and integer in a session under the key "counter":

var count = new Local.Integer("counter");

This is the generic version of the above example:

var count = new Local.Var<int>("counter");

To manipulate the integer, we use the Value property as follows:

 count.Value = count.Value + 10;

To specify a source type, we use the Sources enum given below:

public enum Sources 
{
None = 0,
Session = 1,
Cookie = 2,
Query = 4,
Cache = 8,
SharedCache = 16,
ServerCookie = 32
}

SharedCache uses the default cache object provided in ASP.NET and is shared amongst all users. However Cache will always include the user's unique session ID within its key thus making it unique for each user. So to create an object that will manipulate an integer within a cookie, we can use the declaration below:

var count = new Local.Integer("counter", Sources.Cookie); 

Being generic in nature, and using Json serialization under the hood for text based storage types, we can use the example below to access any object type, say Person, stored within the query string:

var person1 = new Local.Var<person>("person_1", Sources.QueryString);

Now there is yet another way to access variable keys, more especially those having a common prefix. Here is how:

var persons = new Local.Var<person>("person", Sources.QueryString); 
var person1 = persons[1];

var person2 = persons[2];

This will automatically map requests for person1 and person2 to the keys {""person_1" and "person_2""} respectively. Note that "_" is the default delimiter used to separate the parent and the child key. It is also the default key delimiter used with cookies since they inherently support parent/child keys. Furthermore you are allowed to specify several source types sequentially such that if the former type returns a null value, the next coming source will be used instead.

var person1 = new Local.Var<person>("person_1", Sources.QueryString, Sources.Cookie); 
Person person = person1.Value;

person1.Value = new Person();

In the above example, person1 will retrieve its value from the cookie only after an attempt made to retrieve it from the query string has been unsuccessful. The new value being assigned in the last line of code is saved to ALL sources mentioned. But what if, say, we do not want to write to the query string, since this would cause a page refresh, and would rather write to the cache instead? Here is how:

var person2 = new Local.Var<person>("person_1", Targets.Cookie + Targets.Cache, 
Sources.QueryString, Sources.Cookie);

The example above uses the Targets structure to specify target types. The latter is similar to the Sources enum except that its elements are declared as bytes. Person2 will behave exactly like person1 when its value is being retrieved. However any value it is assigned is saved to the Cookie and the Cache instead.

Note that you can call the ToString() function on any object having a generic type to obtain its Json representation. More usage examples are found in the demo code.

Cookies automatically clear themselves when they grow beyond the size limit of 4Kb and query strings have a maximum size of 2048Kb. Note that an error is thrown whenever the query string grows beyond its size limit but the same cannot be achieved for cookies because I haven't found a way to determine their size yet. So the best I could do to avoid size limit issues is implement the compression ability.

Better documentation for this project will be added with time if it gets enough traction from the community and meanwhile, of course, your suggestions, questions and critics are most welcome.

Future Plans

  1. Add ability to use web services as persistence mechanism
  2. Enhance the actual server cookie implementation
  3. Add web farm support using MemCache and/or Velocity (.NET 4.0 only)

History

  • 3rd November, 2009: Initial post
  • 1st December, 2009: Article updated

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here