title: SessionID changing across different instances in Azure (and probably in a web farm)
body: <p>I have a problem with an Azure project with one WebRole but multiple instances that uses cookieless sessions.  The application doesn't need Session storage, so it's not using any session storage provider, but I need to track the SessionID. Apparently, <a href="http://forums.asp.net/t/1655772.aspx/1?Is+session+id+itself+travelling+in+the+cookie+values+" rel="nofollow">the SessionID should be the same accross the WebRole instances</a>, but it changes suddently w/o explanation. We are using the SessionID to track some data, so it's very important.</p>
  
  <p>In order to reproduce the issue:</p>
  
  <ol>
  <li><p>Create a <strong>Cloud Project</strong>.</p></li>
  <li><p>Add a <strong>ASP.NET Web Role</strong>. The code already in it will do.</p></li>
  <li><p>Open <code>Default.aspx</code></p></li>
  <li><p>Add a control to see the current <code>SessionID</code> and a button to cause a postback</p>
  
  <pre><code>        &lt;p&gt;&lt;%= Session.SessionID %&gt;&lt;/p&gt;
          &lt;asp:Button ID="Button1" runat="server" Text="PostBack" onclick="Button1_Click" /&gt;
  </code></pre></li>
  <li><p>Add a event handler for button that will delay the response a bit:</p>
  
  <pre><code>protected void Button1_Click(object sender, EventArgs e)
  {
      System.Threading.Thread.Sleep(150);
  }
  </code></pre></li>
  <li><p>Open <code>Web.Config</code></p></li>
  <li><p>Enable cookieless sessions:</p>
  
  <pre><code>&lt;system.web&gt;
          &lt;sessionState cookieless="true" /&gt;
  &lt;/system.web&gt;
  </code></pre></li>
  <li><p>Run the project, and hit fast and repeteadly the <strong>"PostBack"</strong> button for a while giving attention to the session id in the address bar. Nothing happens, the session id is always the same :). Stop it.</p></li>
  <li><p>Open <code>ServiceConfiguration.csfg</code></p></li>
  <li><p>Enable four instances:</p>
  
  <pre><code>&lt;Instances count="4" /&gt;
  </code></pre></li>
  <li><p>Ensure that in the Web.config there is a line related with the machine key that has been added automatically by Visual Studio. (at the end of system.web). </p></li>
  <li>Rerun the project, hit fast and repeteadly the <strong>"Postback"</strong> button for a while and give attention to the session id in the address bar. You'll see how the <code>SessionID</code> changes after a while.</li>
  </ol>
  
  <p>Why is this happening? As far as I know, if all machines share the <code>machineKey</code>, the session should be the same across them. With cookies there are no problems, the issue apparently is just when cookieless sessions are used.</p>
  
  <p>My best guess, is that something wrong is happening when there are several instances, when the <code>SessionID</code> generated in one <code>WebRole</code> goes to another, is rejected and regenerated. That doesn't make sense, as all the <code>WebRole</code>s have the same <code>machineKey</code>.</p>
  
  <p>In order to find out the problem, and see it more clearly,  I created my own <code>SessionIDManager</code>:</p>
  
  <pre><code>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) &amp;&amp; formerSessionID != base.CreateSessionID(context))
                 // Debugger.Break();
  
              return formerSessionID;
          }
          else
          {
              return base.CreateSessionID(context);
          }
      }
  }
  </code></pre>
  
  <p>And to use it change this line in the WebConfig:</p>
  
  <pre><code>    &lt;sessionState cookieless="true" sessionIDManagerType="WebRole1.MySessionIDManager" /&gt;
  </code></pre>
  
  <p>Now you can see that the <code>SessionID</code> doesn't change, no matter how fast and for how long you hit. If you uncomment those two lines, you will see how ASP.NET is creating a new sessionID even when there is already one.</p>
  
  <p>In order to force ASP.NET to create a new session, just a redirect to an absolute URL in your site: </p>
  
  <pre><code> Response.Redirect(Request.Url.AbsoluteUri.Replace(Request.Url.AbsolutePath, String.Empty));
  </code></pre>
  
  <p>Why is this thing happening with cookieless sessions?</p>
  
  <p>How reliable is my solution in <code>MySessionIDManager</code> ?</p>
  
  <p>Kind regards.</p>
  
  <p><strong>UPDATE</strong>:</p>
  
  <ul>
  <li><p>I've tried this workaround:
  <a href="http://msdn.microsoft.com/en-us/library/gg494983.aspx" rel="nofollow">User-Specified Machine Keys
  Overwritten by Site-Level Auto
  Configuration</a>, but the problem
  still stands.</p>
  
  <pre><code>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 =&gt; (string)e["key"], e =&gt; (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();
  }
  </code></pre></li>
  <li><p>I've also tried this about <a href="http://wiki.asp.net/page.aspx/1229/maintaining-the-session-id-through-out-the-session/" rel="nofollow">put a
  session start handler</a> and add
  some data, but no luck.</p>
  
  <pre><code>void Session_Start(object sender, EventArgs e)
  {
      Session.Add("dummyObject", "dummy");
  }
  </code></pre></li>
  </ul>
  
  <p>Bounty up!</p>