Redis会话状态提供程序使会话无效

时间:2015-01-12 19:31:56

标签: asp.net asp.net-mvc session caching redis

我正在使用NuGet RedisSessionStateProvider

使用ASP.Net会话状态

我正在使用以下内容从应用程序中使用会话数据:

public UserSessionData GetUserSessionData()
{
    if (HttpContext.Current.Session == null || HttpContext.Current.Session["Key"] == null)
    {
        UserSessionData sessionData = ReadSessionFromDatabase();
        HttpContext.Current.Session.Add("Key", sessionData);
        return sessionData;
    }
    else
    {
        return (UserSessionData)HttpContext.Current.Session["Key"];
    }
}

使用上述方法,第一次从数据库中读取值并存储在Session(Redis Cache)中。下次从Redis缓存中读取请求的值而不转到SQL。

工作正常。有时,当我需要使缓存的值无效并强制从数据库读取时,我调用HttpContext.Current.Session.Abandon()。当用户更改他的计划时,这是作为示例完成的。

想象一下我需要使缓存无效的情况,因为数据库中的某些更改但是此更改不是用户的触发器。此更改由另一个网站(管理用户的某个内部网站)完成,或由Webhook(用户的计划更改通知)完成。如何强制用户重新从数据库中重新获取数据(删除缓存数据)什么时候不在HttpContext中触发?

我测试了使用flushdb刷新所有redis缓存并且它有效。但是当然它会强制所有用户会话再次读取数据。如何仅为某些用户使缓存无效?

1 个答案:

答案 0 :(得分:1)

如果你在应用程序内,你可以做Session.Abandon()。但是在这里你要从外部应用程序中删除Redis中的会话。只要您知道应用程序名称(您在web.config中提供的名称)和会话ID,就可以执行此操作。

会话数据作为_ 数据存储在Redis中,一些支持的内部数据存储在 内部。如果用户同时运行另一个页面,您可能会看到 _Write_Lock。

如果从Redis中删除所有三个,它基本上相当于执行Session.Abandon()。如果您打算使用StackExchange.Redis使用C#程序执行此操作,那么我建议使用LUA脚本将其删除,这样三个将立即删除,其他命令都无法干预。

您应该找到一个可以修改数据库条目的地方,并在必要时运行此代码。

string applicationName = "<Actual Application Name>";
string sessionId = "<Actual Session Id>";

RedisKey dataKey = String.Format("{0}_{1}_Data", applicationName, sessionId);
RedisKey internalKey = String.Format("{0}_{1}_Internal", applicationName, sessionId);
RedisKey writeLockKey = String.Format("{0}_{1}_Write_Lock", applicationName, sessionId);

RedisKey[] keys = new RedisKey[3];
keys[0] = dataKey;
keys[1] = internalKey;
keys[2] = writeLockKey;

string removeSessionScript = (@" 
    redis.call('DEL',KEYS[1])
    redis.call('DEL',KEYS[2])
    redis.call('DEL',KEYS[3])"
    );

db.ScriptEvaluate(removeSessionScript, keys, null);