Ran into a stupid problem...
So right now I implement Application_Start to load up the hash tables, which works fine. Next in Session_Start I parse a user's cookie to retrieve his name, which, again, works fine. The problem happens when I store his username in a variable in Global.asax.cs. I didn't really realize that this is a variable shared among all processes/threads. So I guess my question is how do you parse a user's cookie one time and then save the data for sure elsewhere in the process/thread.
You can store cookies in session and use it later. You can store any object in session collection and retrieve it later before it expires. You can read more over here
Assigning to session
Session["anyName"] = "value";
Retrieving from session object
string str = Session["anyName"].ToString();
That's exactly what the ASP.NET session is meant for. Store this information there. It will be only specific to the current user and not shared among all users.
By the way you might also want to checkout Forms Authentication in ASP.NET, just to make sure that you don't reinvent some wheels.
Can't you just use Session?
Session["username"] = username;
var username = Session["username"];
Session is definitely the way I would go. Having HUGE amounts of data in Session could potentially lead to performance problems, but only storing small strings for each user shouldn't matter at all.
Related
I'm building a website with ASP.NET MVC3. When a user signs in, I pull their display name from the database and store it to a session variable:
Session["DisplayName"] = user.Display;
Then in _Layout.cshtml I use it to display at the top of each page:
<span class="user">#(Session["DisplayName"] as string)</span>
This works fine when I start debugging the website then log in, but if I then rebuild my server and begin debugging again, my browser remains logged in but the Session variables are cleared. This leads to a bunch of empty spaces where my display name should be.
Is this a side-effect of rebuilding the server, and not something I need to worry about in deployment? Is there a way to invalidate logins every time I rebuild, so that I avoid this issue? Or is there a better way to store this user data, other than a Session variable?
Is this a side-effect of rebuilding the server, and not something I
need to worry about in deployment?
Oh no, that's something that you absolutely should worry about. As you know ASP.NET session is by default stored in server memory. And when the AppDomain is recycled (which could happen at absolutely any time) by IIS all your session is gone. For example IIS could bring down the AppDomain after a certain inactivity on the application. Or after certain CPU or memory usage thresholds are reached. If you want to be able to reliable store something in the ASP.NET session you could offload the storage off-proc and store this session either in a dedicated session server or SQL. But honestly, I have seen many people moving ASP.NET Session to SQL Server and regretting it. What's the point? You already have this information in SQL Server :-) I once used this and regretted it so much.
Personally I never use ASP.NET Session in my applications. If you need to persist such information as the display name and avoid hitting the database at each request you could store it in the User Data section of the Forms Authentication cookie. So here's the idea: when the user successfully inputs correct credentials, you manually create a FormsAuthenticationTicket and populate its UserData property with whatever information you want to be available about this use on each request and then emit the authentication cookie. Then you write a custom Authorize attribute in which you decrypt the cookie, fetch the User Data and store it as a custom IIdentity making it available on each request.
Store usernames in cache (Cache[string.Format("DisplayName_{0}", User.Id)] = User.Username), cookies or move session to SQL Server instead of InProc
I would create a static helper method that gets username by user id. If it finds cached value, it will use that, if not, get value from db, store it in cache and return.
public static string GetUsername(int UserID)
{
string cacheKey=string.Format("DisplayName_{0}", UserID);
if (HttpContext.Current.Cache[cacheKey]==null)
{
// Retrieve user name from DB
string Username=Repository.GetUserName(UserID);
HttpContext.Current.Cache[cacheKey]=Username;
}
return HttpContext.Current.Cache[cacheKey].ToString();
}
There are better ways, but to address your specific issue your auth timeout and session timeout are not the same, you need to handle the case specifically when one will timeout before the other. See my post here:
How can I handle forms authentication timeout exceptions in ASP.NET?
When user logs in there are number of attributes I need to retrieve from ActiveDirectory such as their real name, some contacts etc. Some of these fields I will be showing quite often in some forms. ActiveDirectory retrieval speed is pretty bad in my case, so I was wondering what would be the best way to store this information in memory when they log in, and then delete it once they log off/timeout?
My thoughts so far:
1) Store in Session, but is it safe?
2) Extend the User.Identity and store it there. Not sure that's possible.
3) Store it in some kind of global Dictionary. How would I know that they logged off to remove the key/value pair?
I am using MVC2 for this project and I will not need to write back to ActiveDirectory.
Session objects are quite commonly used for storing information. If you are worried about security, you can use HTTPS for communication or you can make use of State Servers or SQL Server for storing that information.
Yes as it is said you can use profile provider to store the data.
I personally use session data.
my view why:
1, Database solution via adding field into profile (as additionalUserData = data in here)
Make it simple to use and does not take long to implement as session handling.
2, session data are always on server and there for you do not need to care about data in database, and works without it. (few project has been done this way)
it is reasonably save and easy to access and you can add expiry date time. Also you can keep more information about the user.
3th option:
You would have to have timestamp and checking every request which has expired and remove this records in which case you would have to have dictionary for every user...
The problem is yours....
Hope it helps
I would put it in session as long as it's not a large amount of data. Seems like it's a perfect fit for session state. There shouldn't be any safety concerns if you use https.
If you're concerned about the amount of data you'd be putting in session state you could also consider using the ASP.NET Profile Provider but you'd need to have some type of mechanism to keep the data synched with AD (maybe each time the user logs in). That being said, if it's not a huge amount of data I think session is the way to go.
I'd like to store a few variables which will be referenced throughout lifecycle, starting with a db access in PreInit event. ViewState isn't an option, since it won't persist if saved so early during the page lifecycle. Given that data should not be altered by a user, what would be the best alternative?
You could use the Session to store your data. I am not sure on the number of users of your system, but assuming the data you want to store is small this won't be a problem.'
Also, unless you are using a SessionPageStatePersister (or another server side persister) or encrypting your ViewState it is still possible for the user to change the ViewState. It may be harder, but it is still possible. By default ViewState uses HiddenFieldPageStatePersister and it stores the ViewState in a hidden field on each page (as an encoded string). Just something worth considering.
Depending on the scope: Session or Application
Session
If you want the data stored per user
Application
If you want the data stored available for all users
You could store data in hidden fields, and if you want to obscure it, you could use some kind of encription. Of course these values would also only load in a later stage of the page lifecycle. The session object would be the obvious choice, although it's not everybody's favourite method.
Session probably wouldn't be available at PreInit, but you could store them in variables until a later page lifecycle task, and then store them in session at that time. I could be wrong about the session feature. Additionally, cache is an option but caching is not user-specific; you can make it user specific by appending their user ID or session ID.
Session is probably your best bet. We have to use the session to store some user information, but hit a bug due to accessing it too early. The bug is [HttpException]: Session state has created a session id, but cannot save it because the response was already flushed by the application." But it will often manifest as PageRequestMangerParserErrorException. Super fun hunting that down. One hackish fix is to write into your Global.asax code behind:
public Session_Start(object sender, EventArgs e)
{
string sessionId = Session.SessionID;
}
Accessing the SessionID forces the ASP.NET engine to go build the session before it normally would, making it possible to use it early.
Outside of session (or application) you have two other options: client storage and persistent storage. The latter is a fancy way of saying "stuff it in the database", though similar alternatives exist, of course.
Client Storage is like viewstate, but more controlled. You can use hidden fields or cookies. In fact, a cookie might work out well for you, but you'll need to encrypt the information in it if you want the user to leave it alone. Regardless, anything you send to the client you must assume is compromised, so always do a validity check.
I have a weird issue with session variables. I'm storing some credentials in sessions variables like this:
Session["login"] = "foo";
Session["password"] = "oof";
The page is deployed on a certain server. After I logged in on the page, I noticed that other users (who are in the same network area) calling the page were logged in as well! I thought those data would be stored only for me (I suppose the server sends me back some cookies to ensure that) but that's not the case?
I certainly have a lack of knowledge somewhere. What's going on?
Thanks
I wouldn't recommend storing a password in a session variable for security purposes. If you must use a session variable, do not store the password in clear text. Use some encryption method instead.
Check your web.config
http://msdn.microsoft.com/en-us/library/h6bb9cz9.aspx
In an asp.net application, i would like to use a webservice to return the username associated with the session id passed as a parameter. We're currently using InProc session store.
Is it possible to do this ?
Edit: what i'm trying to do is get information about another session than the current one. I'm not trying to get the SessionID, i've already got it. I'm trying to get the user information associated with a given SessionID.
Thanks,
Mathieu G.
You could possibly create a "fake"cookie with the session ID and make a request to your web service using it, so that the web service was fooled into thinking you were part of the session, enabling you to read any info from it. Sounds like quite the hack, though :)
Something like:
HttpSessionState ss = HttpContext.Current.Session;
HttpContext.Current.Response.Write(ss.SessionID);
That will get the current sessionID.