My biggest concern was performance though. I did not want to make a database write for every request, as I thought it would make the read requests slower. So here is what I have done:
I have created a UserActivity table with columns like: IPAddress, Uid, UserName, CretOn, Url. If a user is logged in then I put the username in the UserName column, it is empty otherwise. If user is not logged in only Uid is filled out with a guid I generate for everyone who visits the site for the first time. Than I store the Uid in a persistant cookie, so that I can track the movement of unauthenticated users as well.
Ok so, the interesting part is how do I insert the data in this UserActivity table?
- Reporter class: Reporter class has an Activities property that is a list of UserActivity. The class has an Add method that puts an activity in the Activities list, and it has a Report method, that inserts everything into the database from the Activities list and empties the Activities.
public void Add(UserActivity activity) { lock (this) { Activities.Add(activity); if (Activities.Count >= ReportingTreshhold) { Monitor.PulseAll(this); } } } public void Report() { List
copyOfActivities; while (true) { try { lock (this) { Monitor.Wait(this); copyOfActivities = Activities; Activities = new List (); } // Report the Activity to the database ReportingEntities reportingdb = new ReportingEntities(); foreach (var item in copyOfActivities) { reportingdb.UserActivities.AddObject(item); } reportingdb.SaveChanges(); } catch (Exception ex) { ExceptionHelper.RaiseErrorSignal(ex); } } } - Start a background thread in Global.asax: For the reporting thing to run I start a background thread when the application starts in the Global.asax.
Thread reporterThread = new Thread(new ThreadStart(Reporter.Report)); reporterThread.Start();
- As I have an ASP.NET MVC application I have created a ReprotingFilter that runs on every request and adds a UserActivity to the Activities list.
public void OnActionExecuted(ActionExecutedContext filterContext) { UserActivity activity = new UserActivity(); HttpRequest currentRequest = HttpContext.Current.Request; // We filter out search engines if(!currentRequest.Browser.Crawler){ // Create the UserActivity Object here... Application.Reporter.Add(activity); } }