We help IT Professionals succeed at work.

Updating a Cache Object in C#

WebAppDeveloper
on
I have a cache object in C# that still has not expired yet, and I want to update the value of its key. How do I do that? This is for an ASP.NET MVC web app.  For example:

UserLogin userLogin = new UserLogin() {
  LoginAttempts = 1,
  DateTimeAttempted = DateTime.Now
};

if (System.Web.HttpContext.Current.Cache["LoginInfo"] == null)
{
   System.Web.HttpContext.Current.Cache.Insert("LoginInfo", userLogin, null, DateTime.Now.AddSeconds(60), TimeSpan.Zero);
}

if (System.Web.HttpContext.Current.Cache["LoginInfo"] != null && UserAuthenticationFailedAgain)
{
   userLogin.LoginAttempts = 2;
   userLogin.DateTimeAttempted = DateTime.Now;
   // Now how do I update the value of this existing cache object's key "LoginInfo" so that the when I access Cache["LoginInfo"].LoginAttempts and Cache["LoginInfo"]. DateTimeAttempted, I get 2 and an updated date time, respectively??  I don't see System.Web.HttpContext.Current.Cache.Update() in docs.microsoft.com
}


Many thanks in advance.
Comment
Watch Question

David Johnson, CDSimple Geek from the '70s
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
don't worry about it.. if you change the item then the cache will realize that the item and the cached item are not identical so it will reload the item. 

Author

Commented:
Ok I will try it again and see if it works
Senior Developer
CERTIFIED EXPERT
Commented:
As you're caching a reference type, the change is reflected automatically, cause there is only one instance in memory. But your code should look like this:

UserLogin userLogin = (UserLogin)System.Web.HttpContext.Current.Cache["LoginInfo"];
if (userLogin == null)
{
    userLogin = new UserLogin() { LoginAttempts = 1, DateTimeAttempted = DateTime.Now };
    System.Web.HttpContext.Current.Cache.Insert("LoginInfo", userLogin, null, DateTime.Now.AddSeconds(60), TimeSpan.Zero);
}

if (UserAuthenticationFailedAgain)
{
    userLogin.LoginAttempts = 2;
    userLogin.DateTimeAttempted = DateTime.Now;
}

Open in new window

You should consider moving the creation and cache handling into static class methods of your UseLogin class. E.g. something like:

public class UserLogin{
    // Your original members and methods.

    private readonly string CacheKey = "LoginInfo";

    public static UserLogin CreateNew()
    {
        UserLogin result = new UserLogin() { LoginAttempts = 1, DateTimeAttempted = DateTime.Now };
        System.Web.HttpContext.Current.Cache.Insert(CacheKey, result, null, DateTime.Now.AddSeconds(60), TimeSpan.Zero);
        return result;
    }

    public static UserLogin Current()
    {
        UserLogin result = System.Web.HttpContext.Current.Cache[CacheKey];
        if (result == null)
        {
            result = CreateNew();
        }

        return result;
    }

    // new methods
    public void AuthenticationFailed()
    {
        userLogin.LoginAttempts += 1;
        userLogin.DateTimeAttempted = DateTime.Now;
    }
}

Open in new window

Then your use-case looks like this

if (UserAuthenticationFailedAgain)
{
    UserLogin.Current.AuthenticationFailed();
}

Open in new window

CERTIFIED EXPERT

Commented:
There's potentially a larger problem with the code though, you may want to look at reworking it a bit.
The HttpContext.Current.Cache is NOT specific to users, it's global for the app domain.

So EVERY single user that attempts to login, is going to share and update the same instance of "LoginInfo" as you have it now.

If User A fails 5 times, and then User B attempts to log in, you'll be getting the same item User A updated.