Forum Discussion
Session values lost on switching server with statesession in asp.net webform with webfarm blue/green
Hi,
I have an asp.net webform website implementing blue/green architecture to get smooth deployment.
The blue/green is a webfarm using ARR in IIS 10 and the website use ASP.NET State Service. The site blue and green are on the same server (same IIS) as the ASP.NET State Service. The web.config contains the correct configuration to get the webfarm work correctly
- <sessionState mode="StateServer" stateConnectionString="tcpip=loopback:42424" cookieless="false" timeout="20"/>
- MachineKey and validationkey identical
When we swap the blue/green website, the user can smoothly continue his navigation on the website (same sessionid used by the user on both website each time we swap).
However, the values in the session do not follow up. They seem to be compartmentalised by each website. I finally found a possible explanation stating that in a webfarm, the website should have the same ID so the session values follow. Load-Balanced IIS 7.5 Web Server ASP.NET Session State problem - Server Fault
My problem is that I can't have the 2 websites having the same ID because they are in the same IIS (same server). Is there any workaround or setting I can change to correct that behaviour?
Thank you,
- LanHuangMicrosoft
Hi JfFerland,
Thanks for posting your issue here.
However this platform is used for how-to discussions and sharing best practices for building any app with .NET.Since your issue is a technical question, welcome to post it in Microsoft Q&A forum, the support team and communities on Microsoft Q&A will help you for any technical questions.
Besides, it will be appreciated if you can share it here once you post this technical question Microsoft Q&A.
Best Regards,
Lan Huang- jf_ferlandCopper Contributor
LanHuang Thank you for the reply.
I posted as proposed on the Q&A Forum : Session values lost on switching server with statesession in asp.net webform with webfarm blue/green - Microsoft Q&A
- MarioElianCopper Contributor
Can you please share the custom solution here, I also trying something relevant, If I add this feature in my project so it would put great impact.
I would be thankful to you.
Regards- jf_ferlandCopper Contributor
MarioElian Yes, here's my final solution and it work great in production.
As said earlier, you must make sure the basic configuration for webfarm are in place (same machine key, sessionState mode="StateServer"). Now your user will not lose his session while switching website instance. However, the value in his session will not transfer. To correct that problem you add the following code in your global.asax.
/// <summary> /// Variable used to initialize the execution of code using reflection to correctly operate session /// variables once (or a few times due to concurrency). The variable is static so its scope is for /// the current application loaded in memory. When loading a new instance of the site (blue/green), /// a new “instance” of the static variable is in memory and therefore the application will go /// through reflection again to correctly initialize the session. /// </summary> private static bool hasInitializedApplicationName = false;
/// <summary> /// This is a hack so that the values in the session variable are shared between the web sites /// of a server farm. There is a configuration in the web.config called ApplicationName which /// will be injected into the module that isolates session values (different if classic/integrated mode). /// So, the first user(s) will modify this value in the module that is loaded so that sessions are /// shared correctly for everyone. /// *The value that is overwritten corresponds to a combination of the physical path of the website /// and the site ID in IIS. For this to work without a hack, the second website must be on another /// server with the same path AND the website must have the same ID. Quite fragile…” /// </summary> private void InitializeASPNETSession() { if (hasInitializedApplicationName) return; try { // Get the app name from config file... string appName = ConfigurationManager.AppSettings["ApplicationName"]; if (string.IsNullOrEmpty(appName)) return; foreach (string moduleName in this.Modules) { IHttpModule module = this.Modules[moduleName]; SessionStateModule ssm = module as SessionStateModule; if (ssm == null) continue; FieldInfo storeInfo = typeof(SessionStateModule).GetField("_store", BindingFlags.Instance | BindingFlags.NonPublic); SessionStateStoreProviderBase store = (SessionStateStoreProviderBase)storeInfo.GetValue(ssm); if (store == null) //In IIS7 Integrated mode, module.Init() is called later { FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic); HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null); FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", BindingFlags.Instance | BindingFlags.NonPublic); appNameInfo.SetValue(theRuntime, appName); hasInitializedApplicationName = true; //We change the static variable here so the next calls avoid doing reflection. By the nature of the requests, it's possible that the code get exectuted multiple time but it's acceptable and will not cause side effect. break; } else //IIS Classic and localhost debug IISExpress { Type storeType = store.GetType(); if (storeType.Name.Equals("OutOfProcSessionStateStore")) { FieldInfo uribaseInfo = storeType.GetField("s_uribase", BindingFlags.Static | BindingFlags.NonPublic); uribaseInfo.SetValue(storeType, appName); } hasInitializedApplicationName = true; //We change the static variable here so the next calls avoid doing reflection. By the nature of the requests, it's possible that the code get exectuted multiple time but it's acceptable and will not cause side effect. break; } } } catch (Exception ex) { //Log the error } }
public override void Init() { base.Init(); InitializeASPNETSession(); }
That's it. I hope it help and save you some precious time.
- jf_ferlandCopper Contributor
You need to add the following setting in your web.config under appSettings to make everything work together
<appSettings> <add key="ApplicationName" value="WEBSITE_NAME" />