locked
Session variable still disappears and reappears! (caution: long and difficult) RRS feed

  • Question

  • User260076833 posted

    Hello,

    I have a serious problem using session variables in my application.

    Problem:

    • I set a session variable "testVariable" to the value "testValue".
    • Then, the variable disappears and reappears:
      After each reload or redirect triggered by the user behavior:
      Sometimes the variable is present and sometimes it is not.

    Minimal example:

    I found this problem in a large application, but I reduced it to a minimal example in one single aspx file.

    • The example shows a table with all the session attributes including the variables.
    • There are three LinkButtons:
      • Set: This sets the variable "testVariable" to the value "testValue" and redirects to the same page.
      • Reload: This reloads the page.
      • Redirect: This redirects to the same page.

    Look what happens: I have made a screen recording here (please ignore the variable "dummyVariable" for now).
    As you can see, the variable "testVariable" appears after repeatedly clicking on "Reload" and "Redirect". It also disappears and reappears then.

    I can see this behavior with different intensities on MS Edge, MS IE and Chrome (Edge is the worst).

    I have attached the minimal code example below.

    (Note that another mysterious behavior is that as soon as I don't set the variable "dummyVariable" in Page_Load, I get a new Session ID on every reload!
    But this is not the focus here.)

    Environment:

    Now to the most important point: The minimal example works as expected on my development machine: I click on "Set" and the variable "testVariable" appears immediately and it doesn't disappear when clicking on Reload or Redirect! The problem only occurrs in the production environment!

    The production environment is a IIS based web farm in the data center. I don't have access to the configuration of this web farm, but I actually have a conversation with an admin in the data center who is responsible for the web farm. I assume that the problem must have something to do with the fact that there are more nodes where the application is running on and that the session must get lost somehow. But also the admin has no idea...

    Questions:

    • What can the admin in the data center do? Where should he look in the configuration?
    • How can I come closer to an explanation? Can I do more tracing or something like that?
    • Since sessions are stored on the server, why is the behavior slightly different in different browsers?
      With MS Edge I need to click a dozen times on Reload or Redirect until the variable appears. In IE and Chrome, the variable appears immediately, but it disappears when leaving the browser alone for 2-3 minutes (The session should hold longer.)

    Any help is welcome!

    Magnus

    Default.aspx:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="LostSessionData.v06.Default" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
        
            <h1>Session Test</h1>
    
            <table>
                <tr>
                    <td>
                        <asp:LinkButton ID="btn_Reload" runat="server" Text="Reload" PostBackUrl="Default" />
                    </td>
                    <td>
                        <asp:LinkButton ID="btn_Redirect" runat="server" Text="Redirect" OnClick="btn_Redirect_Click" />
                    </td>
                    <td>
                        <asp:LinkButton ID="btn_Set" runat="server" Text="Set" OnClick="btn_Set_Click" />
                    </td>
                </tr>
            </table>
    
        <table id="tbl" runat="server" border="1">
    
            <tr>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label2" runat="server" Text="Session ID:"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;" >
                    <asp:Label ID="lbl_sid" runat="server" Text=""></asp:Label>
                </td>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label13" runat="server" Text="Timeout"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_Timeout" runat="server" Text=""></asp:Label>
                </td>
            </tr>
    
            <tr>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label9" runat="server" Text="Codepage"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_Codepage" runat="server" Text=""></asp:Label>
                </td>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label12" runat="server" Text="Contents"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_Contents" runat="server" Text=""></asp:Label>
                </td>
            </tr>
    
            <tr>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label14" runat="server" Text="CookieMode"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_CookieMode" runat="server" Text=""></asp:Label>
                </td>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label16" runat="server" Text="Count"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_Count" runat="server" Text=""></asp:Label>
                </td>
            </tr>
    
    
            <tr>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label7" runat="server" Text="isCookieLess"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_isCookieLess" runat="server" Text=""></asp:Label>
                </td>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label3" runat="server" Text="isNewSession"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_isNewSession" runat="server" Text=""></asp:Label>
                </td>
            </tr>
    
            <tr>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label4" runat="server" Text="isReadonly"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_isReadonly" runat="server" Text=""></asp:Label>
                </td>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label5" runat="server" Text="isSynchronized"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_isSynchronized" runat="server" Text=""></asp:Label>
                </td>
            </tr>
    
            <tr>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label8" runat="server" Text="LCID"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_LCID" runat="server" Text=""></asp:Label>
                </td>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label10" runat="server" Text="Mode"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_Mode" runat="server" Text=""></asp:Label>
                </td>
            </tr>
    
            <tr>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label11" runat="server" Text="StaticObjects"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_StaticObjects" runat="server" Text=""></asp:Label>
                </td>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label15" runat="server" Text="SyncRoot"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;">
                    <asp:Label ID="lbl_SyncRoot" runat="server" Text=""></asp:Label>
                </td>
            </tr>
    
            <tr>
                <td style="text-align:right;padding:10px;">
                    <asp:Label ID="Label6" runat="server" Text="Variables:"></asp:Label>
                </td>
                <td style="text-align:left;padding:10px;" colspan="3">
                    <asp:Label ID="lbl_Variables" runat="server" Text=""></asp:Label>
                </td>
            </tr>
    
        </table>
    
        </div>
        </form>
    </body>
    </html>
    

    Default.aspx.cs:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace LostSessionData.v06
    {
        public partial class Default : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                // if you remove this line then you get a new session id on every reload! #-)
                Session["dummyVariable"] = "dummyValue";
    
                lbl_sid.Text = Session.SessionID;
    
                lbl_Codepage.Text = Session.CodePage.ToString();
                lbl_Contents.Text = Session.Contents.ToString();
                lbl_CookieMode.Text = Session.CookieMode.ToString();
                lbl_Count.Text = Session.Count.ToString();
    
                lbl_isCookieLess.Text = Session.IsCookieless ? "1" : "0";
                lbl_isNewSession.Text = Session.IsNewSession ? "1" : "0";
                lbl_isReadonly.Text = Session.IsReadOnly ? "1" : "0";
                lbl_isSynchronized.Text = Session.IsSynchronized ? "1" : "0";
    
                lbl_LCID.Text = Session.LCID.ToString();
                lbl_Mode.Text = Session.Mode.ToString();
                lbl_StaticObjects.Text = Session.StaticObjects.ToString();
                lbl_SyncRoot.Text = Session.SyncRoot.ToString();
    
                lbl_Timeout.Text = Session.Timeout.ToString();
    
                lbl_Variables.Text = getVariables();
    
            }
    
            public String getVariables()
            {
                String s = "";
    
                for (int i = 0; i < Session.Keys.Count; i++)
                {
                    String t = Session.Keys[i];
    
                    if (!String.IsNullOrEmpty(s))
                        s += ",";
                    s += (t + "=" + Session[t]);
                }
    
                return (s);
            }
    
            protected void btn_Set_Click(object sender, EventArgs e)
            {
                Session["testVariable"] = "testValue";
                Response.Redirect("Default", false);
            }
    
            protected void btn_Redirect_Click(object sender, EventArgs e)
            {
                Response.Redirect("Default.aspx", false);
            }
    
        }
    }

    Friday, May 19, 2017 6:56 AM

All replies

  • User475983607 posted

    Your test has bugs.  After I fixing the bugs I was unable to reproduce the stated Session issues.

    Friday, May 19, 2017 4:07 PM
  • User260076833 posted

    Hello,

    could you please tell about the bugs?

    Thanks
    Magnus

    Tuesday, May 23, 2017 7:56 AM
  • User260076833 posted

    Hello,

    I cannot imagine a bug in the above test code that causes a session variable to disappear and reappear. If this is really caused by a bug, then let me know.

    In addition: I also cannot reproduce the problem on a single machine. It only occurrs on the web farm...

    Magnus

    Wednesday, May 24, 2017 4:59 AM
  • User-271186128 posted

    Hi Yeoman,

    According to your description, your web application was run in the web farm, that's meant more than 2 servers would process request. if your session state mode is InProc, that's would occurred error.

    So, you should change your session state mode to StateServer or SQLServer, and you should use the same StateServer Or SQLServer each on your server, about more detail how to configure it you could refer the following link.

    https://msdn.microsoft.com/en-us/library/ms178586.aspx

    Also, you should use the same machine key each on your server, you could refer the following links.
    https://forums.asp.net/t/2121144.aspx
    https://technet.microsoft.com/en-us/library/cc731979(v=ws.10).aspx

    Best regards,
    Dillion

    Wednesday, May 24, 2017 5:51 AM
  • User260076833 posted

    Dear Dillion,

    thank you very much! I never cared about the session mode. But according to your explanations, I am sure this will solve the problem.

    But unfortunately, I do not control the web farm and the database in the production environment. These systems are running in a data center. In addition, the administrators there are no developers. So I have to tell them what I need as precisely as possible.

    I am open for both, StateServer mode and SQLServer mode:

    • StateServerMode
      I don't know anything about the web farm. Officially, I don't even know that it's a web farm. The data center only provides a FTP access where I can upload my application.
      So I cannot tell which server to set the "stateConnectionString" attribute to.
      Can this be just one of the farm nodes?
      How would you ask the web farm administrator to provide such a server?

    • SQLServerMode
      My application uses a SQL database. Can I use just the existing connection string in my web.config for the "sqlConnectionString" attribute?
      If yes, how can I reuse the existing variable "configuration.connectionString" without repeating the string itself?
      Can I just use my own database? If yes, are additional tables required for the session data?
      If no, do I need another database for my session data?
      Again: How would you ask the database administrator to provide such a server?

    Thank you
    Magnus

    Wednesday, May 24, 2017 7:12 AM
  • User-271186128 posted

    Hi Yeoman.

    According to your description of the last reply, I suggest that you could use SQLServerMode,the connection string you only need to provide the datasource, userid and password such like this:

    <system.web>
        <sessionState mode="SQLServer" sqlConnectionString="Data Source=192.168.0.10\SQL2008R2;User ID=sa;Password=123456" >
    </sessionState>
    <system.web>
    

    You could use the same sql server which you using now, but the user which you configured need the permission to create new database.

    If you want to use StateServerMode,
    (1)You should start Asp.Net State Service on one of the server.
    (2)Configure web.config.

    <system.web>
        <sessionState mode="StateServer" 
           stateConnectionString="tcpip=(your server's address which start Asp.Net State Service):42424" 
           cookieless="false"  
           timeout="20"/>
    <system.web>
    

    Don't forget to configure machine key, it's also very important.

    Best regards,
    Dillion

    Wednesday, May 24, 2017 8:26 AM
  • User260076833 posted

    Dear Dillion,

    I have just spoken with the admin of the web hosting service, and he told me that my application isn't running in a web farm (any more).
    This is totally confusing to me, because I thought that there is a solution now with your recommendations.

    What does this mean now? Are all the configuration settings discussed above obsolete now?

    I asked him to send me a screenshot of the IIS session settings.
    But where should I go from here?

    Thanks
    Magnus

    Wednesday, May 24, 2017 9:37 AM
  • User475983607 posted

    Consider using a cookie rather than Session as the browser always sends cookies to domain that created the cookie. I would craft a class that has all the properties you want. Populate the class, JSON serialize the class and encrypt.  Finally insert the encrypted JSON token into a cookie.  Do the opposite when reading the cookie.  In this scenario state is maintained in a cookie and always passed from the client to the server.  

    This might sound like a lot of steps but it is pretty simple and you only have to write the code once.

    I explained why Session was not a good idea in one of your previous thread with the same subject. 

    https://forums.asp.net/p/2116687/6120557.aspx

    Wednesday, May 24, 2017 10:51 AM
  • User1967761114 posted

    Hi ChenArc,

    According to your video ,that’ so strange.

    The Session ID never change ,but the values are all missing ,according to this,I think your web app is working in the web farm.

    Could you also output the computer’s name and check whether use the same computer?

    If you have any other questions, please feel free to contact me any time.

    Best Regards

    Even

    Friday, May 26, 2017 10:13 AM
  • User260076833 posted

    Dear Even,

    thank you for pushing this thread again. I was somewhat frustrated, because I first thought I found an issue with the web farm, but then I heared that it's only a single machine.

    I also still cannot accept the advice of mgephard, not to use sessions at all. I believe that most of the web applications make use of sessions. They may have disadvantages, but I cannot believe that the problem shown at the beginning of this thread is solely results from the use of sessions.

    You asked me to output the machine name. I added the value of System.Environment.MachineName to the output. I had a little hope that it would change on reload, so that we had a hint that the admin told me something wrong and that the application would really run on a web farm with different nodes on different requests. But unfortunately, the machine name doesn't change, so it seems to be a single machine.

    So, we have the same session ID, the same machine name, but a variable which disappears and reappears...  still totally straying in the dark... :-(

    However, today I see another hint: Sometimes, when the variable is missing, the "isNewSession" attribute is "1", allthough the session ID did not change. I don't know what this may tell us, but I see it as another weird behavior...

    And I also see another hint: The behavior is different in Edge and IE. While you need a lot of reloads in IE until the variable disappears, it's not present from the beginning (click on "Set") in Edge. Why could there be differences?

    I believe that this behavior cannot be simply the result of using sessions. If this was the case, then no one would ever use sessions at all.
    There must be something else and I would be glad if we can find it...

    Thanks
    Magnus

    Tuesday, May 30, 2017 11:51 AM
  • User475983607 posted

    I also still cannot accept the advice of mgephard, not to use sessions at all. I believe that most of the web applications make use of sessions. They may have disadvantages, but I cannot believe that the problem shown at the beginning of this thread is solely results from the use of sessions.

    I think giving the cookie a try makes perfect sense as a cookie is half of the Session framework.  If you put a bit of information in a cookie and run the same test.  Heck, you can even test both the cookie and Session side by side.  If the cookie persists and Session does not then you know the cookie (and Session cookie) are always making their way to the server.  If the cookie and Session behave the same, the data disappears and reappears, then there is a different issue and you can focus your time accordingly.

    Tuesday, May 30, 2017 1:54 PM
  • User585649674 posted

    Session is used to identify whether the request is coming from an existing connection. Each session has an Id, stored in cookie. You can set Cookieless = true and view the session id in the url. 

    <system.web>
        <sessionState mode="InProc"
          cookieless="true"
          timeout="20"/>
      </system.web> 

    Now open IE / edge and do your test scenarios, loading / reloading / click on address bar and enter. Verify the session id bieng passed. 

    On the server side, all session variables are created and maintained for each instance of session Id. A session id will be allocated to the first request, populate the session variables as and needed on the server.

    It is the responsibility of the client i.e the browser to send the same session id back, so that it can retreive the session values saved in previous requests.

    Session can be cleared by Session.Clear or Session.Abandon. Or even due to timeout. Try hooking to session_onend to see if your sessions are ending.

    https://msdn.microsoft.com/en-us/library/ms178583.aspx

    Web server restart can also clear sessions

    Tuesday, June 27, 2017 9:56 AM