Given a function that returns the total number of active users on the website:
private static readonly object Lock = new object();
public static int GetTotalActiveUsers()
{
var cache = HttpContext.Current.Cache;
if (cache["ActiveUsers"] == null)
{
lock (Lock)
{
if (cache["ActiveUsers"] == null)
{
var activeUsers = 5; // This would actually be an expensive operation
cache.Add("ActiveUsers", activeUsers, null, Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration,
CacheItemPriority.Normal, null);
}
}
}
return (int) cache["ActiveUsers"];
}
The problem with storing a ValueType in the cache in this way is it's not updatable. For example:
public static void OnNewActiveUser()
{
var total = GetTotalActiveUsers();
total++;
}
Doesn't update the cached value. (This is an expected behaviour).
I'm looking for a thread safe method to update the active user count.
Use a lock
public static void OnNewActiveUser()
{
lock (UpdateActiveUsersLock)
{
var cache = HttpContext.Current.Cache;
var newTotal = GetTotalActiveUsers() + 1;
cache.Insert("ActiveUsers", newTotal, null, Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration,
CacheItemPriority.Normal, null);
}
}
Create a thin class around the int to turn it into a reference type:
public class CachedInt
{
public int Int { get; set; }
public CachedInt(int value)
{
Int = value;
}
}
Then:
public static void OnNewActiveUser()
{
var activeUsers = GetTotalActiveUsers();
activeUsers.Int++;
}
I'd prefer to avoid Solution 1 if possible (it doesn't fit neatly into my design). Is wrapping the value types in a thin class code smell, or is it a legitimate way to solve the problem?
HttpContext.Current.Cache caches objects (reference types), so you need to wrap the int (value type) in a reference type, as you suggested.
By why not just have a class with a static method and a static member for count if the cached item will never expire?
Also, you should use interlocked increment to ensure the count is correct, and have some way of knowing when a user is not active so that the count can be decremented. As pointed out in a comment, this will only give you the count for a single process. If you have multiple web processes on the same machine, or multiple servers the count will be wrong - maybe that's what the expensive operation is that returns 5 :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With