Consider a user making multiple requests at the same time, do I have to lock all code that works with the Session?
If for example I have the following scenario, where in one tab of his browser the user opens a page and in the second he logs out.
Request 1:
if(Session["user"] != null)
lblName.Text = Session["user"].Name;
Request 2:
if(logout)
Session["user"] = null;
Is it possible that Request 1 throws a NullPointerException when accessing the Name property? Do i need to lock the code in Request 1, to make sure user still exists after checking for null? Or does ASP.NET deal with this automatically somehow?
Two requests to an ASP.NET application for the same same session, where the handlers do not use the IReadOnlySessionState marker interface or have the EnableSessionState="ReadOnly" turned on for your pages, will be serialized by the ASP.NET runtime to guarantee consistency of the state. So if you have two pages that are able to write to the session state, they will be accessed serially no matter what the client does on their side.
It's up to your application code to signal to ASP.NET with the afforementioned techniques whether or not a page/handler is going to write to the session state. If you do not, all requests will be serialized and the performance of your web application will suffer.
As always, the answer depends on what you mean by "safety." In ASP .NET, each request gets exclusive access to its session state. This means that you don't have to worry about synchronizing access within the scope of a single request. If Session["user"] is non-null, then it will be non-null for the entire duration of the current request. In your example, request 1 will never throw a null reference exception.
In ASP.NET, the Session module uses a pair of reader/writer locks per session, so Request 1 will have consistent reads, and Request 2 will block until Request 1 completes.
Yes, Session is thread-safe.
There's no need to lock anything. However, the need to check the values never cease to be essential.
Update
Check #Peter Ruderman's answer :)
I will have the decency of not copying it :)
Related
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.
I'm pretty basic with .net
But basically I've been told that to have session stickiness for my website in the environment it is to be deployed means I have to get session from the cookie ASP.NET_SessionId
But what does this mean/how do I use this?
And where I am using my existing session code e.g. Session.Add("Something", something) do I now need to change this?
This is automated for you
You don't have to manually read cookies yourself. Asp.net does it for you. So whenever you access Session dictionary your session will already be preserved if it existed from your previous request(s). If there is none (or expired) it will also be automatically created so adding items to it will make it work without a problem.
So basically instead of accessing Session identifier from a cookies and do whatever with it (as you won't be able to access intrinsic session store), just use Session:
Session["SomeKey"] = myVar;
// or
Session.Add("SomeKey", myVar);
and for reading
var o = Session["SomeKey"];
Are cookies mandatory?
Basically Asp.net supports other means of session ID storage apart from cookies. You can enable cookieless session if you wanted to (a setting in web.config file). Session identifier will be added to your URL like:
http://www.example.com/(S(lit3py55t21z5v55vlm25s55))/orderform.aspx
Read more about it here on MSDN.
What's the default?
By default session identifier is preserved in cookies. That means that you don't have to change anything in web.config. But if you'd like to use other means you'd have to set that in web.config (check the same upper link as before).
Typically the way that I use session variables in ASP.NET is like this
// set
Session["SessionVariableName"] = localVariable;
// get
localVariable = Session["SessionVariableName"] as LocalType; // then check nulls
The issue with any sessions is that if you don't go out of your way to change it, the default stores sessions in-proc so every time IIS recycles a worker process your session is lost. This can be easily fixed by using the built-in ASP.NET State Service. A quick search turned up this article on using it.
You can get a reference to the current session in multiple ways but the most easy way is just use the session property on the page.
See:
http://msdn.microsoft.com/en-us/library/system.web.ui.page.session.aspx
Session stickiness is not a feature of ASP.net, but rather of a load balancer that may sit in front of it. If you are using InProc sessions, then the session data is stored in the server's memory. With "sticky" sessions, the load balancer will send all requests from the same source (based on IP usually) to the same server to ensure that the session always exists.
This isn't the most scalable way to handle a web farm scenario. Microsoft introduced two other mechanisms, StateServer and SqlServer which serve to send the session data to a single location for all web front ends.
You likely just need to make sure you don't have cookieless set to true in your configuration.
Regardless of how this is all configured, you will always retrieve your session data the same way - ASP.NET abstracts the details away.
// Set
Session["mySession"] = "Hello World";
// Get
var s = Session["mySession"];
I need to maintaing the Session throughout the day? On or before session expires, how do I enforce session throughout the day without giving any session timeout either in IIS or web.config?
Note: Default Session Timeout in IIS – 20 minutes.
Thanks in Advance
The first thing you can do is decouple the session from the process by using a SQL (or other database) session state server that holds the serialized copy of the session data attached to a session id. Then you could use a persistent cookie to pass the session id back and forth. Any session that expires could then be regenerated or reinstated.
Since you're wanting to maintain a session all day (which is innately insecure), we'll assume that most security considerations have already been thrown out. If you're concerned about replay attacks, you could use an HMAC to validate cookie session requests by having the session id, datetime, username (if that's part of your data), maybe IP address in a string followed by a one-way salted hash of this data. This way you rehash the data and compare the hash sent with the request with the generated hash from that data to see if the request is valid.
Forcing the page to be refreshed every 10 minutes or so by javascript. The session timeouts are how long after the last requested page, the session becomes invalid. When you refresh the page every 10 minutes or so, the session is extended for 20 minutes on every refresh.
If you refuse to change the setting in the web.config to a longer value, you could try to force the browser to refresh within a short time of the session timeout (eg at 17 minutes). There might be other nifty ways.
If you can find a way to do without the session, it will save you pain later. Either use a caching strategy (memcached) or look at your resource usage.
eg Do you really need to serialise X into the session?
Use StateServer instead of InProc
This delegates all session handling to a separate database and removes it from the servers process. This will mitigate problems with eating up server resources which then allows you to increase the session timeout to 24 hours.
I believe this is the only viable solution.
Peiter is on the right track -- making fake requests to keep things alive. You definitely don't want to refresh the page, that leads to unwanted updates and such. You don't even need to refresh part of the page. You just need to send an ajax request every X minutes while a user has a browser open to an IHttpHandler that does have session state enabled. This is very, very effective -- we've got one app which is compltely dependent upon sessions for everything that has a 5 minute session timeout. And a session heartbeat that fires every 4.5 minutes. Its been in production upwards of 3 years and we have not lost a session yet. And yes, session state is stored in process in this case -- the use of sessions is so heavy we don't want to wait for them to go out to SQL and back.
PS: protip -- make sure to make the request and response unique; caching kicks in otherwise in certain browsers rendering this trick ineffective.
put a ajax call into a timer, to a method which does nothing "", that's how even the user is on the page but not doing anything means "totally inactive", would not log out, we have implemented the same logic and resolved our problem, our target was 3 to 4 hours, and we did not want to change the value in web.config or using any other way cause of some reasons.
that ajax call would be in a "timer", set the timer time to "any".
I've the following doubt. I've a page "MyPage" and i've declared few dictionary objects in the page class.
My doubt is
If i declare the dictionary as a private non-static object i'm not able to use it across the functions in that page class (the object is getting nulled)
But if i declare the dictionary to be static i'm able to across the object across the functions. But will that object be same across all the users who have opened the page right now (guessing that each user will have an instance of the page in turn has an instance for the page class and static variables of a class are invariable across all the instances of the class)
Is my understanding right? How to declare the object to be available across all the functions within the page class and unique for each instance of the page (user).
Update1
Okie, i find that the initialization of the dictionary object in the page class is done in a different thread (WCF Duplex callback). But in the main page thread the dictionary object is still remaining as null (uninitialized). Any ideas?
Update2
Marshalling - useful by any chance?
Update3
In reply to John-
Thanks for your reply. The problem i'm facing now is to pass the data from the WCF callback class at the client side(which will be invoked in a separate thread) to the asp.net page. So how can i do that? View state may help me to persist the data across requests. But when the callback is invoked by the server notifying for a change how should i pass the changes (data) to the UI thread (asp.net page)?
Don't do things like this.
If you need to maintain data between pages, use Session state. That's what it's for. You should remember that you get a new instance of your page class on every request. Do not use statics to keep changing data around for subsequent requests. You will probably get into trouble with multiple requests updating the data at the same time.
You can't do things like this with ASP.NET!
You seem to be treating this as though it were a desktop program - as though your class instance and all state will still be there for you next time you execute a method on the page. That's not true - when the request is complete, your page will be Disposed. Nothing about the page will remain valid.
In particular, if the callback doesn't happen before the request ends, then the callback method had better not reference anything having to do with the request, like your page. That's because the callback might fire after the request is already over! The state is corrupt or worse.
Unless you are going to have the page wait for the callback, you'd really better not use them in your pages. Instead, create a separate Windows Service or something and have it issue the requests and await the callback. The page can then use Ajax or something to ask if the request is complete, and to get the response once complete.
If you think you heard me say to call back to an ASP.NET page, then you misunderstood.
Create a Windows Service. Your Windows Service will host a WCF service that the ASP.NET application will talk to. The WCF Service will keep track of things like who's joined a chat, who's typing, etc.
The web application cannot be notified when something interesting happens. Instead, the web application will have to poll the WCF service, asking if anything interesting has happened. When something happens, the WCF service will pass the "something" back to the ASP.NET application (or possibly, back to the page, called by AJAX).
I misspoke earlier. You simply cannot use a callback contract at all in this situation. It's not like the web pages are like a desktop application, one per user, waiting to be notified. They're more like a desktop application where, when the user makes a request, you take his PC and give him a new one just like it, before the response arrives.
You are right in the second case. In your first case I'm guessing you mean that if a user clicks multiple controls on your page then the event handlers are seeing that the dictionary is null (instead of having the result from the previous event handler).
Remember that every request on a page (even from the same user) creates a new instance of your page class. That means that each time a request starts, your dictionary will be null. The only way for a variable to maintain its value between subsequent requests is to persist it server-side (for example, in user-specific session information on the server) or to push it to the client with the page content so that it can be part of the subsequent request data (so it's stored in ViewState or other storage at the client's browser between requests).
Rereading this question, there are three seperate state machines, and none of them are being coupled together - hence the problem :)
State of the "user state" - these are the key/value pairs in the dictionary, their lifetime spans multiple page requests and callbacks
State of a "page", which needs to consume the data from "user state". Pages are destroyed after each and every page request.
State of the "service call" which needs to populate the data in "user state" Service calls are generally destroyed after each invocation.
There are a few strategies that could enable you to couple the systems:
ViewState such that the state machine for "user state" is sent down as part of the state of the page, and sent back on postbacks. This may constrain how you perform service callbacks
Session such that the state machine for "user state" is stored server side, and can be accessed by key.
Static dictionary of user states, where the key for the outer dictionary would be the identity of the "user state", where the 1st page request would create the "user state" entry, and you'd need to manage teardown. (v.similar to session - though works without ASP.NET).
There are lots of nuances to each solution - I'd advise light reading :)
you are right that a static member will be the same for all instances of the page, and thus all individual users. You need to make it a non-static member if you want to access it from every method in the class. You should look into why the object is null. Are you properly instantiating it at the proper time?