语言: ASP.NET Core MVC 中的 C# 和 HTML Razor
上下文/问题; 在 Visual Studio 中调试时,我使用 HttpContext.Session 存储特定于用户的信息,按预期在注销操作函数中调用 HttpContext.Session.Clear() 并清除所有会话变量。但是,当将同一应用程序发布和部署到 IIS 时,单击注销,会话变量被清除,但大约 10 - 12 秒后,会话变量重新出现,就像它们从未被清除一样......有时也有这样的情况:会话确实保持清除状态,但大多数情况下都会出现此问题。
这会导致注销按钮将用户注销大约 10 秒,然后用户信息重新出现,从而使网站看到用户再次登录。
从我的代码中截取:
家庭控制器:
[Route("logout")]
[HttpGet]
public IActionResult Logout()
{
HttpContext.Session.Clear();
return RedirectToAction("Index");
}
cshtml/Razor 视图/页面:
<a class="nav-link text-dark" asp-controller="Home" asp-action="Logout"><b>Logout</b></a>
仅供参考:我正在使用我在网上找到的 SessionExtension,它允许我直接在 Session 中存储对象,而无需手动对它们进行编码/解码。我将用户信息存储为字典,这样我就可以通过页面中的 HttpContextAccessor 轻松访问它,以便在需要时获取权限。我选择了这个,而不是每次需要页面权限时都访问数据库。相反,在登录时访问数据库一次并将收集到的信息存储在会话中。我不确定这是否是造成这种情况的原因,但我想我应该包含这一点以获得更多背景信息。
SessionExtensions.cs:
using Newtonsoft.Json;
#nullable enable
namespace Microsoft.AspNetCore.Http
{
public static class SessionExtensions
{
public static void SetObject(this ISession session, string key, object value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetObject<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
}
}
}
这是我在会话中遇到的唯一问题,用户之间的其他一切同时工作正常,只是注销就是问题。当注销按钮起作用时,其他一切也都可以正常工作。
我尝试过的事情:
使用 VS 调试 IIS 上部署的实例,单击注销按钮后,会话保持清除状态(返回 Null)约 10 - 12 秒,然后所有内容重新出现,就像从未清除过一样。
在我的开发人员上调试项目。单击注销后,VS 内的计算机并没有看到相同的行为,会话将无限期地保持清除状态。 (返回空)
清除客户端浏览器的cookie。
重新启动运行 IIS 和站点的服务器。
从 IIS 中删除站点并重新传输已发布的文件,然后再次添加。对发布设置为“调试”和“发布”的配置执行相同的操作。功能没有变化。
更新所有 NuGet 包,最近还更新到 .NET 7.0 框架。
我可能会遗漏一些东西,因为我对 C#、ASP.NET Core MVC 和 Razor 页面,甚至 Stack Overflow 还很陌生。如果需要添加更多信息来帮助回答问题,请发表评论。
编辑: Program.cs 中设置的会话超时(空闲超时)always正确地清除了会话。
编辑: 我可以通过在单击注销时将每个会话变量设置为 null 来解决此问题。但这似乎是一种绕行的方法,如果我将来添加另一个变量,可能很容易出错。这应该是解决方案吗?
编辑: 我之前提到的将每个变量设置为 null 的修复方法并不能解决所有问题。我实际上注意到会话中出现的其他问题。我无法确定,因为它是随机的,有时设置会话变量不需要,有时需要,有时有时需要......
看起来会话只是忽略了对其方法的一些调用,或者当它跟随它们时,它只生效 10 秒......
编辑: 我已经尝试了一切可以解决这个问题的方法,直到我偶然发现了这个问题。
@{var IPAddress = HttpContextAccessor.HttpContext.Request.HttpContext.Connection.RemoteIpAddress.ToString();
Ping pingSender = new Ping();
PingReply reply1 = pingSender.Send(IPAddress);
PingReply reply2 = pingSender.Send(IPAddress);
PingReply reply3 = pingSender.Send(IPAddress);
long[] ReplyTimes = { reply1.RoundtripTime, reply2.RoundtripTime, reply3.RoundtripTime};}
@ReplyTimes
这是我在调试页面中设置的一小段代码,它可以为我提供平均 3 个样本的当前 ping 值。由于某种原因,删除此代码解决了我迄今为止可以告诉的所有问题。经过进一步研究,似乎每次发生会话更新(更改变量)时,它都会保存更改,然后在 10 秒后恢复。
奇怪的部分是,再过 10 秒后,它有时会再次恢复到最新的变量,然后重复......基本上导致变量自行更改。此调试页面仅在登录时显示,所以我仍然有点困惑此页面上的代码如何影响注销的能力(即使未加载调试页面,会话清除也会在 10 秒后重新出现)
我仔细检查了一下,始终只有 1 个会话 cookie。
我不知道为什么删除此代码可以解决问题。也许以某种方式访问请求远程 IP 地址会导致不可预见的问题?
我将其添加为编辑而不是答案,因为这并不能真正回答为什么这会导致会话按原样运行。
我也有类似的问题。我这样做是为了解决这个问题。
更改:
<a class="nav-link text-dark" asp-controller="Home" asp-action="Logout"><b>Logout</b></a>
致:
<a class="nav-link text-dark" href="/logout"><b>Logout</b></a>
还创建了一个新控制器:
public class LogoutController(ILogger<LogoutController> logger) : Controller
{
private readonly ILogger<LogoutController> _logger = logger;
public IActionResult Index()
{
// Clear the session data
HttpContext.Session.Clear();
Response.Cookies.Delete(".AspNetCore.Session");
return RedirectPermanent("login");
}
}
以及program.cs中的新路由映射
app.MapControllerRoute(name: "logout",
pattern: "{controller=Logout}/{action=Index}/{id?}");