views:

235

answers:

1

I'm developing an Asp.net (MVC but this doesn't really matter) application. I have a custom IHttpModule that's responsible for the PostAuthenticateRequest to change user principal & identity.

I'm storing UserID and UserName in authentication cookie when user logs-in. I have an IUser (implemented by DAO and Business Objects layer, each with their own additional members) that I need all over Business Service classes. When a user wants anything I have to provide IUser object instance (usually from Business Objects layer) so providing ID from the auth ticket isn't sufficient.

So I'm thinking of how and where would be best to persist logged in user's IUser data?

  1. I don't want to fetch it every time from the DB (based on authentication ticket's UserID data)
  2. I can't store it in Session since I have to work inside PostAuthenticateRequest, where Session isn't ready yet
  3. I want all the functionality to be encapsulated within my custom IHttpModule

Choices that I see:

  • Cache
  • Cookie
  • (Session) - by moving from PostAuthenticateRequest to PostAcquireRequestState event and change principal/identity there, but I'd like to avoid this

Processes that seem to complicate things are:

  1. User logs-in, user data is fetched from the DB and persisted somehow for later requests
  2. User logs-out, user data has to be removed from persisted medium automagically
  3. User changes own profile, user data has to be discarded and reread on next request from the DB

I wan't all these to be handled automatically by HttpModule (if possible) to eliminate developer's errors of forgetting to reset these things.

What I also don't want is to write/read some hardcoded variables/keys and manipulate them in other parts of the application. This would only present technical debt.

Questions

  1. What would you suggest?
  2. How does SO persist user data between requests?
+3  A: 

Given your requirements, I suppose the best solution is to retrieve the ID from the cookie and use it to index into the Http Cache (HttpContext.Current.Cache).

If you want to maintain how users access it, wrap the Cache in a "UserCache" object. The object could be constructed by an HttpModule and stored as a (wait for it...) singleton within the cache itself or, better yet, just constructed when needed to pull from the http cache. This would depend on where you need to access it and whether HttpContext.Current.Cache is directly available. The lazy implementation is below.

Again, this is for clarity and is not how I'd actually implement it.

public class UserCache
{
  public IUser GetUser(object userKey)
  {
    return HttpContext.Current.Cache[userKey];
  }

  public void AddUser(object userKey, IUser user)
  {
    /* this could pull the key from the user object as well. */
    HttpContext.Current.Cache.Add(/* add the object with key and a sliding expiration that is slightly greater than session timeout */);
  }

  public void ExpireUser(object userKey)
  {
    HttpContext.Current.Cache.Remove(userKey);
  }

  /* If you don't want to do SQL cache dependency */
  public void UpdateUser(object userKey, IUser user)
  {
    HttpContext.Current.Cache.Insert(/* ... */);
  }
}

Using the default caching mechanisms (or better yet a caching mechanism supplied by DI so you're not tied to an implementation), you can set an expiration to automatically remove users from the cache as mentioned in the comment. You can setup the cache to be dependent on SQL server updates as well to handle the updates or manually update it as part of the service to save changes.

More information about the default cache is available here. More information about cache dependencies is available here.

In the HttpModule itself, I suppose you could do some magic in the EndRequest event to see if the request is authenticated and then log the user out based on the cookie, but I'm not sure if that would work as I've never tried it. You might want to have a look at this article on MSDN from WAY back in the 1.1 days and see if it answers some of the problems you are trying to solve.

As for the SO architecture and how they do it, I'd imagine they load it when needed because they keep most of the database in RAM at all times (http://highscalability.com/stack-overflow-architecture).

andymeadows