情景:
运行运行.NET 3.0的服务器和在启用了Web园的应用程序池中运行的ASP.NET网站(进程数:3)。 web.config配置如下:
<sessionState cookieless="UseCookies" cookieName=".authz" mode="StateServer" regenerateExpiredSessionId="true" stateConnectionString="tcpip=127.0.0.1:42424" timeout="60" useHostingIdentity="true" />
现在将计算机升级到.NET 3.5 SP1。重新启动服务器。结果:不再在w3wp.exe的实例之间维护会话,就好像所有会话都还原为InProc一样。目前的解决方法是减少到1个工作进程。
奇怪的是:不同服务器上的相同代码没有遇到任何问题。我之前遇到过这个问题,但重启后神奇地消失了。我已经重启了一次,但到目前为止还没有快乐。
比较两台服务器的两台machine.configs和web.configs:相同。
Someone else has experienced this problem,但没有答案。
有什么想法吗?我真的难以接受这个。
答案 0 :(得分:11)
所以,这个很棒。
如果满足以下所有条件,则会出现问题:
当升级完成并重新启动服务器时,您会发现刷新页面时会丢失会话变量,因为只有1/3的机会获得原始工作进程以满足您的原始请求。但这并不重要,因为您正在使用ASP.NET状态服务。什么破了?
使用ASP.NET状态服务时,ASP.NET使用一个名为machineKey
的值来加密和/或散列要存储的所有会话数据(我不知道它是加密还是散列,或者两者都是,但这不是这次讨论的重要区别)。这样,当任何工作进程使用会话标识符从服务请求数据时,可以确保数据在存储在外部数据源中时未被篡改。
如果您在Web场中,则可能在machineKey
文件中定义了静态web.config
,并且不会发生此问题。但对于单服务器Web园方案,您可能依赖于默认的machineKey
设置,该设置对于ASP.NET 2.0应用程序设置为AutoGenerate,IsolateApps
。这意味着ASP.NET会自动生成应用程序池独有的计算机密钥。它根据某种算法重新生成此密钥,但这对于此讨论并不重要。
生成的值通常存储在HKLM\SOFTWARE\Microsoft\ASP.NET\2.0.50727.0\AutoGenKeys\{SID of the Application Pool Identity}
下的注册表中。但是.NET Framework安装程序错误(我确实认为这是一个错误)会破坏此注册表项,并且为了加重侮辱,会重置此密钥的权限,以便您的自定义应用程序池标识无法写入注册表项创建新的机器密钥。
结果是,在Web园中旋转的每个工作进程都使用它自己及时生成的机器密钥的内存副本,从而有效地创建了Web场景。例如,工作进程A旋转,看到没有AutoGenKey
条目存在(实际上,它甚至不能读取它),生成它自己的并开始使用它来散列发送到ASP的数据.NET状态服务。它尝试将此新计算机密钥保存到注册表项,但无提示失败。工作进程B旋转,看到没有AutoGenKey
条目存在,生成自己的条目并开始使用 来散列数据...你会看到它的去向。
现在结果是您使用三个不同的机器密钥对会话数据进行了哈希处理。虽然会话标识符的数据存在,但三个工作进程中有两个会将其拒绝为无效/篡改,因为它使用自己的密钥。
您可以通过在machineKey
文件中明确设置自定义web.config
来解决此问题。
或者您可以在命令提示符处重新运行aspnet_regiis.exe -ga MachineName\ApplicationPoolUserName
以修复损坏的权限。
你的问题解决了。是时候睡觉了。
6月30日更新:根据我在Microsoft Connect上对此问题的报告,Microsoft已表明他们已修复安装程序,以便在升级到.NET时不会发生此行为4.所有未来的3.0 / 3.5升级仍然可能发生,所以我会留下这个问题/答案。