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);
我正在使用 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);