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

Redis Session State Provider invalidate session

我正在使用 ASP.Net 使用 NuGet RedisSessionStateProvider 的会话状态。

我正在使用类似这样的应用程序使用会话数据:

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"];
    }
}

通过上面的方法,第一次从Database中读取值并存储到Session(Redis Cache)中。下次请求值时,将从 Redis 缓存中读取,而不会转到 SQL.

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

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

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

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

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

如果从 Redis 中删除所有这三个,它基本上等同于执行 Session.Abandon()。如果您打算使用 C# 程序使用 StackExchange.Redis 执行此操作,那么我建议使用 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);