我对一个具有一个 WebRole 但多个使用无 cookie 会话的实例的 Azure 项目有疑问。该应用程序不需要会话存储,因此它没有使用任何会话存储提供程序,但我需要跟踪 SessionID。显然,SessionID 在 WebRole 实例中应该是相同的,但它会突然改变而没有解释。我们正在使用 SessionID 来跟踪一些数据,所以它非常重要。
为了重现该问题:
创建一个云项目。
添加ASP.NET Web 角色。已经在里面的代码就可以了。
打开
Default.aspx
添加一个控件以查看当前
SessionID
和一个按钮以导致回发<p><%= Session.SessionID %></p> <asp:Button ID="Button1" runat="server" Text="PostBack" onclick="Button1_Click" />
为按钮添加一个事件处理程序,这将稍微延迟响应:
protected void Button1_Click(object sender, EventArgs e) { System.Threading.Thread.Sleep(150); }
打开
Web.Config
启用无 cookie 会话:
<system.web> <sessionState cookieless="true" /> </system.web>
运行该项目,然后快速反复点击“PostBack”按钮一段时间,注意地址栏中的会话 ID。没有任何反应,会话 ID 始终相同:)。停下来。
打开
ServiceConfiguration.csfg
启用四个实例:
<Instances count="4" />
确保在 Web.config 中有一行与 Visual Studio 自动添加的机器密钥相关。(在 system.web 的末尾)。
- 重新运行项目,快速并重复点击“回发”按钮一段时间,并注意地址栏中的会话 ID。
SessionID
一段时间后你会看到变化如何。
为什么会这样?据我所知,如果所有机器共享machineKey
,它们之间的会话应该是相同的。使用 cookie 没有问题,问题显然只是在使用无 cookie 会话时。
我最好的猜测是,当有几个实例时发生了错误,当一个SessionID
生成的实例WebRole
转到另一个实例时,被拒绝并重新生成。这没有意义,因为所有WebRole
s 都具有相同的machineKey
.
为了找出问题并更清楚地看到它,我创建了自己的SessionIDManager
:
public class MySessionIDManager : SessionIDManager
{
public override string CreateSessionID(HttpContext context)
{
if (context.Items.Contains("AspCookielessSession"))
{
String formerSessionID = context.Items["AspCookielessSession"].ToString();
// if (!String.IsNullOrWhiteSpace(formerSessionID) && formerSessionID != base.CreateSessionID(context))
// Debugger.Break();
return formerSessionID;
}
else
{
return base.CreateSessionID(context);
}
}
}
要使用它,请在 WebConfig 中更改这一行:
<sessionState cookieless="true" sessionIDManagerType="WebRole1.MySessionIDManager" />
现在您可以看到,SessionID
无论您击打多快和多长时间,它都不会改变。如果取消注释这两行,您将看到 ASP.NET 如何创建一个新的 sessionID,即使已经有一个。
为了强制 ASP.NET 创建新会话,只需重定向到站点中的绝对 URL:
Response.Redirect(Request.Url.AbsoluteUri.Replace(Request.Url.AbsolutePath, String.Empty));
为什么无 cookie 会话会发生这种情况?
我的解决方案有多可靠MySessionIDManager
?
亲切的问候。
更新:
我已经尝试过这种解决方法: User-Specified Machine Keys Overwritten by Site-Level Auto Configuration,但问题仍然存在。
public override bool OnStart() { // For information on handling configuration changes // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357. using (var server = new ServerManager()) { try { // get the site's web configuration var siteNameFromServiceModel = "Web"; // update this site name for your site. var siteName = string.Format("{0}_{1}", RoleEnvironment.CurrentRoleInstance.Id, siteNameFromServiceModel); var siteConfig = server.Sites[siteName].GetWebConfiguration(); // get the appSettings section var appSettings = siteConfig.GetSection("appSettings").GetCollection() .ToDictionary(e => (string)e["key"], e => (string)e["value"]); // reconfigure the machine key var machineKeySection = siteConfig.GetSection("system.web/machineKey"); machineKeySection.SetAttributeValue("validationKey", appSettings["validationKey"]); machineKeySection.SetAttributeValue("validation", appSettings["validation"]); machineKeySection.SetAttributeValue("decryptionKey", appSettings["decryptionKey"]); machineKeySection.SetAttributeValue("decryption", appSettings["decryption"]); server.CommitChanges(); _init = true; } catch { } } return base.OnStart(); }
我也试过这个关于放置一个会话启动处理程序并添加一些数据,但没有运气。
void Session_Start(object sender, EventArgs e) { Session.Add("dummyObject", "dummy"); }
赏金!