I have a single-page, .NET 4.7.1 MVC application. My Page_Load() for Default.aspx.cs sets session variables and, when my breakpoint at the last line of Page_Load() is hit, the session object is stored correctly. However, when I click a link and hit my breakpoint on the first line of Page_Load() for the second call, HttpContext.Current.Session has no session variables set. Also, HttpContext.Current.Session.SessionID changes after the first call and then remains the same. Subsequent calls work correctly but the first one after an app pool recycle is always empty.
I have no httpCookies entry in the web.config and I'm always accessing via HTTPS. The app is running in an azure app service and I'm using OpenID Connect for authentication. Under what circumstances are variables removed from HttpContext.Current.Session before timing out?
UPDATE: I've added some diagnostic logging and sometimes SessionID changes without dropping the actual session data. I don't know how this can be but thought I'd record it. Also, it appears that my logging of the session ID has fixed the problem. I've seen others mention that the session is not preserved until it's been accessed (which is happening) but (without having searched exhaustively) I suspect all the session reading and writing in the first call is taking place in other assemblies and therefore perhaps not being 'counted' as reason to preserve the session? This seems very hokey but is my only guess for now. I'm still confused why it would have started breaking now.
Related
Languages: C# and HTML Razor inside ASP.NET Core MVC
Context/Issue; I am storing user-specific information using HttpContext.Session, when debugging in Visual Studio calling HttpContext.Session.Clear() in my logout action functions as expected and clearing all Session variables. But when publishing and deploying the same app to IIS, clicking logout, the Session variables are cleared, but after approximately 10 - 12 seconds the Session variables re-appear like they never were cleared... There are also sometimes instances though where the Session does stay cleared, but a majority of the time it has this issue.
This results in the logout button logging the user out for about 10 seconds, then the user information re-appears thus making the website see the user as logged in again.
Snips from my code:
Home Controller:
[Route("logout")]
[HttpGet]
public IActionResult Logout()
{
HttpContext.Session.Clear();
return RedirectToAction("Index");
}
cshtml/Razor view/page:
<a class="nav-link text-dark" asp-controller="Home" asp-action="Logout"><b>Logout</b></a>
FYI: I am using a this SessionExtension I found online that allows me to store objects directly in Session without me having to encode/decode them manually. I store the user info as a Dictionary so I can easily access it via HttpContextAccessor in pages to pull permissons when needed. I chose this rather then accessing the database everytime a permission is needed for a page. Instead accessing the database once when logging in and storing the gathered info in Session. I'm not sure if this is somehow causing it but I figured I'd include this bit for more context.
SessionExtensions.cs :
using Newtonsoft.Json;
#nullable enable
namespace Microsoft.AspNetCore.Http
{
public static class SessionExtensions
{
public static void SetObject(this ISession session, string key, object value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetObject<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
}
}
}
This is the only issue I'm getting with Session, everything else works fine between users at the same time, just logging out is the issue. When the logout button does work everything else works fine too.
Things I've Tried:
Debugging the deployed instance on IIS with VS, the Session stays cleared (returns Null) for about 10 - 12 seconds after clicking the logout button, then everything re-appears like it was never cleared.
Debugging the project on my dev. computer inside VS and not seeing the same behavior, after clicking logout Session stays cleared indefinitely. (Returns Null)
Clearing cookies of client browser.
Restarting Server running IIS and site.
Deleting site from IIS and retransferring published files, then adding it again. Did the same with configuration for the publish set to Debug and Release. No change in functionality.
Updating all NuGet packages and also recently updating to .NET 7.0 framework.
I might be missing something as I'm pretty new to C#, ASP.NET Core MVC, and Razor pages, and even Stack Overflow. Comment if more information needs added to help answer the question.
EDIT:
The session timeout (Idle Timeout) set in Program.cs always correctly clears the session.
EDIT:
I could probably fix this by setting every session variable to null when clicking logout. But this seems like a run-around way of doing it and could be prone to errors if I add another variable in the future. Should this be the solution?
EDIT:
My previously mentioned fix of setting each variable to null doesn't solve every issue. I'm actually noticing other issues arising with session. I can't pinpoint because its random, sometimes setting a session variable doesn't take, or sometimes it does, or sometimes it does temporarily...
It's seeming almost like session is just ignoring some calls to it's methods, or when it follows them it only takes effect for 10 seconds...
EDIT:
I've tried everything I could try to fix this issue, until I stumbled across this.
#{var IPAddress = HttpContextAccessor.HttpContext.Request.HttpContext.Connection.RemoteIpAddress.ToString();
Ping pingSender = new Ping();
PingReply reply1 = pingSender.Send(IPAddress);
PingReply reply2 = pingSender.Send(IPAddress);
PingReply reply3 = pingSender.Send(IPAddress);
long[] ReplyTimes = { reply1.RoundtripTime, reply2.RoundtripTime, reply3.RoundtripTime};}
#ReplyTimes
This is a small piece of code I setup in a debug page that would give me my current ping over an average of 3 samples. For some reason removing this code solved all my issues that I can tell so far. After further research it seemed like every time a session update took place (changing a variable) it would save the change then revert back after 10 seconds.
The weird part comes in where after another 10 seconds it would sometimes revert back again, to the latest variable, then repeat... Basically causing the variable to change by itself. This debug page only shows when logged in so I'm still a bit confused as to how this code on this page effected the ability to logout (The session clearing then re-appearing after 10 seconds even with the debug page not loaded)
I double checked and there was still only 1 session cookie the entire time.
I have no idea why removing this code fixed the issue. Maybe somehow accessing the request remote ip address causes unforeseen issues?
I'm adding this as an edit rather then a answer since this doesn't really answer why this is causing session to act the way it is.
I have to implement session handling across multiple users, and multiple browsers. Each user has a unique token which I save in HttpContext.Current.Session variable inside the Session__Start() in Global.asax.cs method. It works perfectly fine for a single session. However, when I fire the request from two browsers, then while browsing through various pages, sometimes the method Session_Start() automatically gets called for the second session and it resets the session variable, resulting in a null value.
How should I handle this scenario?
Edit 1:
What are the scenarios where the session may time out? Eg: switching between HTTPGet/HttpPost, or making Ajax calls?
I also read this link:
Does Session timeout reset on every request
Is this something which I should be keeping in mind? My code has 2 GET and 1 POST request, and the session variable becomes NULL in the POST method for the second browser session.
I figured out the reason. The sessionState mode in web.config file was set to "InProc", whereas it should be set as "StateServer". When I made the necessary change, then it worked like a charm.
ASP.net state service should also be started from services.msc for this to work.
I have this piece of code:
var thisUser = Session["user"];
if (thisUser == null)
{
LogFile.Log("Logging out");
Response.Write("xp");
}
I am trying to track down why sometimes when I play with the system for a few minutes and suddenly the user session variable gets null.
It happens randomly in different scenarios.
I do not set the Session["user"] to null at any point.
Session timeout is set to 20 minutes.
I do not call Session.Clear() at any point.
Any ideas\thoughts\things I should look at as to why is it may happening?
I am using Firefox if that to any help.
The system is built with asp.net.
For more info please ask.
are you calling the same host? if the base URL is different the server will treat this as different users. for example:
http://localhost/path/to/resource and http://localhost:80/path/to/resource
both point to the same resource, but the requests are different and the session cookie will be different, or not present.
An easy way to test this is to launch your browser's developer toolbar and monitor the network traffic. compare the URLs to make sure they are the same base path and the same session cookie is passed in the request.
First of all this looks like C# and ASP.NET, not classic ASP. Now if you never clear the session yourself and the server (or the app pool) is never restarted, then the only way to lose the session is to clear the browser's cookies.
Editing the web.config will recycle the app pool, which clears the session info.
Recently I have been asked by a client to log into a legacy site using POST and not GET (from a 3rd party site), All of the needed variables are now sent within a post instead of a query string.
The problem is that upon receiving all of variables they are stored into Session and then redirected to the correct page within the application (from the logo-in Page).
While this works perfectly while calling the page using GET, a POST call will lose all of the Session variables after
Response.Redirect(#"~/SOMEPAGE.aspx",false);
Another thing that is odd is that the Session ID will remain the same but all values will be gone.
When Using Server.Transfer the session is intact but will be lost once the Response.Redirect is used. (there is no option to change all of the code.)
Does any one know of a way to resolve this or some sort of a work around that might be used.
Thanks!!!
There are a few reasons this could happen.
You are using Session.Abandon() in your code
You are switching between a secure (https://) and insecure (http://) URL
You have some code in your global.asax that is manipulating Session, or the .Secure or .Path properties of your Response.Cookie
edit http://forums.asp.net/t/1670844.aspx
Are we "doing it wrong"?
A colleague and I are messing around with an ASP.NET page to act as a "portal" to view the results from a diagnostic program on a UniData server. Although we do the odd-job of ASP/ASP.NET at work, it is not our primary language.
To access this server, we have to use UniObjects, which is an API for authenticating and using the UniData server.
We needed each user visiting the website to have to authenticate with UniData and get their own session via the UniObjects library, then be able to use it without signing in again (unless the session isn't used with in 'x' minutes).
The method we have come up with is as follows:
We have a singleton with a Hashtable. It maps Windows username with a session object.
If the user goes to our page and 'username' doesn't exist in the Hashtable, it redirects to a login page where the session object is created and added to the Hashtable if authentication succeeds. Otherwise, it grabs the users existing session object from the Hashtable and uses that for the request (unless it has expired, in which case we remove it and redirect to the login page).
Each session object (which is a wrapper object for stuff from UniObjects) has a "lastUsed" method. We need to clean-up user's sessions since we have license restrictions on users logged into the UniData server, so every time a user gets redirected to the sign-in page, it checks if any sessions have not been used in 'x' mins, in which case it closes that session and removes it from the Hashtable. It is done here so users won't experience any delay related to checking all sessions on every request, only at login.
Something is telling me that this solution smells, but I don't have enough ASP.NET experience to work out what we should be doing? Is there a better method for doing this or is it actually okay?
Since all of your users seem to be authenticated, I would suggest you think about using a different way of managing session state and timeout.
Part of the issue you have is that if a user just closes the browser without logging out, or stops using the application, you have to wait until the session times out to kill it off and free up UniObjects for your licensing issues.
My suggestion is as follows:
Add an invisible IFRAME to your
MasterPage template, or to each page
in the site if you aren't using
MasterPages.
That MasterPage will
load a KeepAlive.aspx page, that
contains a META Refresh, reloading
the page every 5 minutes.
You can
reduce the session timeout to 10
minutes (maybe even 6)
Now, if a user closes their browser windows, their session times out much quicker than usual, but if their browser window is left open, their session is persistent.
A code example and walkthrough can be seen here.
You now need to solution to prevent the user from leaving their browser window open all night and hogging your UniData licences. In this case I would implement a similar methodology, where a stagnant page (i.e. user has done nothing for 20 minutes) is refreshed to a logout ASPX page, clearing the session.
If you are using UniObjects COM, make sure you get your COM marshalling working correctly. Take a look at:
SafeCOMWrapper - Managed Disposable Strongly Typed safe wrapper to late bound COM
http://www.codeproject.com/KB/COM/safecomwrapper.aspx
Another thing to watch out for is that the dynamic array class in UniObjects COM has a threading issue that doesn't play nice with .NET. If you can, use your own dynamic array class or array splits in .NET instead of the Dynamic array class in UniObjects COM.
Sometimes when you try to access the data from the class, it shows an empty string, but when you debug it, the data is there. Don't know the root cause of this.
If you need a generic dynamic array class that works with .NET, I can supply you one.
UniObjects.NET does not have these problems to my knowledge.
Nathan Rector
When you say you are using UniObjects... are you using the COM or .NET object set? The easiest would be to use UniObject Conneciton pooling.
When you create your Singleton, are you storing it in the Application object, Session Object, or Cache Object?
I would suggest Application object, as the Session object is can do strange things. One way to handle and check timeouts would be to use the Cache Key with a CacheRemoveCallback. This way you can use a File/Path Monitor dependency to watch for a windows file change to cause a remove manually, or a timeout from the Cache dependency.
Draw back to this is that timeouts on Cache Dependencies are only driven by page activity, and if the asp.net session recycles, it may/will destory the cache dependencies.
Nathan Rector