I have an ASP.NET application that is accessed by 120-140 users at the same time on average. I use Session to get and set user specific info. To make things easy I've got a static a class called CurrentSession and it has a property called UserInfo:
public static class CurrentSession{
public static UserInfo{
get{return HttpContext.Current.Session["userInfo"]!=null?(UserInfo)HttpContext.Current.Session["userInfo"]:null;}
set{HttpContext.Current.Session["userInfo"]=value;}
}
//And other properties
}
And whenever I needed current user's info I just used to do:
CurrentSession.UserInfo;
Recently I've come across situations when wrong user info is retrieved. Is there a problem in my approach that can cause Session conflicts?
No. It can't be that the session change can be caused by the static method. In fact, HttpContext.Current itself is a static. Assigning it to a static variable can cause this.
Related
How can I declare global variables in MVC application without using static ?
I am currently following the static approach and it is causing issues when the application is logged in from different users at the same time.
If you want to make them global per user, I would suggest to use the Session context to save the variables to. This is not really on a user level, since a user can log in multiple times, but usually this suits better in my experience.
I usually have something like this:
public string Prop
{
get
{
return (string)Session["Prop"];
}
set
{
Session["Prop"] = value;
}
}
This will make accessing the property very easy and consistent.
Similar to session you can also use application object. Also you can store variables in cache.
I came across a Singleton implementation in a site I was tasked to make changes to. The only thing I know about Singleton is its definition and as such never had an opportunity to work "with" it. So I started to read articles and this one on Implementing the Singleton Pattern in C# nicely explains it. Except that the code I have looks not quite the same. Can some take a look at this and points out what this code does or how is it different?
public class Singleton<TSingleton> where TSingleton : class, new()
{
private static readonly Lazy<TSingleton> instance = new Lazy<TSingleton>(() => new TSingleton());
public static TSingleton Instance { get { return instance.Value; } }
}
This class is called like this Singleton<AccessLogger>.Instance.LogAccess(accessData); where accessData is an instance of AccessLoggerData and basically contains environment, page and user information. The accessData is an instance of AccessLoggerData class:
public class AccessLoggerData
{
public string Environment = Singleton<ApplicationSettings>.Instance.Environment;
public string Page, UserId;
public AccessLoggerData(string page, string user)
{
this.Page = page;
this.UserId = user;
}
}
Strangely as I'm writing this post and somehow it is becoming more clear as to how these pieces come together, but one thing remains unclear, why would it be necessary to allow only one instance of this accessData object?
This looks like a generic implementation of the singleton pattern using the (newish) Lazy keyword. In its default form it make sure that only a single instance of the object created is accessed (LazyThreadSafetyMode.ExecutionAndPublication). This is important as the initialization code of the object being created might have some side effects that would be undesirable if executed twice. Checkout http://csharpindepth.com/articles/general/singleton.aspx for some more information on this.
"why would it be necessary to allow only one instance of this accessData object?"
It's a little hard to say exactly just based on the code provided. Perhaps multiple users are active on the system at the same time. The class name AccessLoggerData suggests that info is being logged.
You'd only want one instance logging that data if it involves file access. You wouldn't want multiple instances competing for a file write lock. The problem with this is there's nothing to suggest that in the actual code. Maybe it's meant to allow one user at a time and their state is held by this Singleton. In that case, it's bad design. Considering there's another Singleton within AccessLoggerData for application settings, you have a Singleton as a global: not good. It may be Singletonitis by the former developer.
i have a small class with just a couple properties in it.
here is an example:
public class clsRepLogs
public string those;
public string these;
public void setThoseandThese
{
//call a stored procedure
//get results
this.those = something;
this.these = somethingElse;
}}
from my first.aspx.cs
i call the set function:
clsRepLogs cLog - new clsRepLogs()
cLog.setThoseandThese()
so now the properties have been assigned values.
i now want to use them in another aspx.cs file to populate a form... but can't figure out how to get to them...
i tried
clsRepLogs cLog;
lblThese.text = cLog.these;
but it's giving me an error: "Use of unassigned local variable 'cLog'
basically, how do i tell it to use the values i've already assigned to that class instance from before?
i hope i'm explaining this right, but i might be way of on what i'm doing. any help appreciated.
It sounds like you want to access the same instance of the class from multiple ASPX pages. There are multiple ways to do this; a per-user solution is to use session state.
// page 1
var c = new clsRepLogs();
c.setThoseAndThese();
Session["mykey"] = c;
// page 2
var c = (clsRepLogs)Session["mykey"];
"mykey" can be any string. You may also want to check if Session contains the value before accessing it, e.g. if( Session["mykey"] != null ){ ... }
Keep in mind:
Session isn't durable; restarting the web worker process will reset all in-process sessions.
It's usually not a good idea to store many large objects in Session.
If the data is confidential, be aware of Session fixation attacks.
Session can be load balanced across servers, so this solution will scale.
For reference (alternative approaches):
You could use the Cache object when you don't care about per-user isolation and want control over data expiration.
You could use the Application object; similar to Cache but no control over expiration.
You could store the object in the database and load it on each page. This is useful when you to don't want a heavy session, and/or wish to save the data more permanently (such as a shopping cart which persists across multiple sessions).
You need to initialize or set cLog to the instance of clsReport that you want.
You aren't instantiating your class. It should be
clsRepLogs cLog = new clsRepLogs();
Or, if I misunderstood your code,
clsReport cLog = new clsReport();
EDIT:
If you need to preserve these, it should be a static class so that it cannot be instantiated.
public static class clsReport
{
public static string those;
public static string these;
public static void setThoseandThese
{
//call a stored procedure
//get results
this.those = something;
this.these = somethingElse;
}
}
A lot of this depends on how you need this to function. In addition, I'm no expert on perpetuating objects/classes in memory in Webforms applications. If you wanted to re-access the class to get those values, I'm not sure they would still be in memory.
You will need to initialize your cLog class :
clsRepLogs cLog = new clsReport();
lblThese.text = cLog.these;
I have a asp.net project with c# code behind. I have a static class called GlobalVariable where I store some information, like the currently selected product for example.
However, I saw that when there are two users using the website, if one changes the selected product, if changes it for everybody. The static variables seem to be commun to everybody.
I would want to create (from the c# code) some kind of session variable used only from the c# code, but not only from the page, but from any class.
Yes static variables are shared by the whole application, they are in no way private to the user/session.
To access the Session object from a non-page class, you should use HttpContext.Current.Session.
GlobalVariable is a misleading name. Whatever it's called, it shouldn't be static if it's per session. You can do something like this instead:
// store the selected product
this.Session["CurrentProductId"] = productId;
You shouldn't try to make the Session collection globally accessible either. Rather, pass only the data you need and get / set using Session where appropriate.
Here's an overview on working with session storage in ASP .NET on MSDN.
You sort of answered your own question. An answer is in session variables. In your GlobalVariable class, you can place properties which are backed by session variables.
Example:
public string SelectedProductName
{
get { return (string)Session["SelectedProductName"]; }
set { Session["SelectedProductName"] = value; }
}
I have a problem with static variable. Part of the organization of my controllers is as follows:
namespace MyApp.Controllers
{
public class DevicesController : Controller
{
static int some_var = 0;
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SetValue(int temp){
some_var = temp;
return RedirectToAction("DisplayValue");
}
[Authorize]
public ActionResult DisplayValue(){
....
return View(some_object);
}
}
}
The problem arises when multiple users simultaneously using this view. The same static variable is used by all users and change its value. How solve this?
Your entire ASP.NET MVC application runs within an AppDomain, that is the application plus all requests being served for all users, everything!!
When you create a static variable, a single instance is declared and made available to the entire AppDomain, every request from every user will see the same value.
An instance variable (simply remove the 'static' word) is specific to an instance of the particular object it's in. In this case the object is an instance of your Controller, so your variable as an instance variable will be individual/specific to that controller object only. The ASP.NET runtime will create an instance of your Controller for each request it serves, then discard that controller object once its processed the request. So if you remove the static word, the variable will only stay around for the duration of that request, then disappear.
What you need, as other posters have said, is Session state. Session State lasts the duration of a session, as in someone browsing your site, and is specific to each user. So if you store that variable in Session State, it will be different for each user.
Problem is Session state disappears when the user leaves your website, so if you need it to the stay around longer, you then should use something like a database.
From your comments and original post, it sounds (and I'll try to put this as politely as possible) that you haven't quite grasped some Object-Oriented Programming idioms and concepts. While Session state isn't a OOP concept per se, the difference between static and instance variables is. I would recommend brushing up on these, as an understanding in these concepts (fundamental to OO programming) would mean, IMHO, you wouldn't even be asking this very question. I hope this answer has helped in your understanding somewhat.
You can use,
HttpContext.Current.Session["some_var"]
instead of some_var, this will help. This will preserve for the user that is logged, one session, and you can access it statically with HttpContext.Current
namespace MyApp.Controllers
{
public class DevicesController : Controller
{
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SetValue(int temp){
HttpContext.Current.Session["some_var"] = temp;
return RedirectToAction("DisplayValue");
}
[Authorize]
public ActionResult DisplayValue(){
....
return View((int)HttpContext.Current.Session["some_var"]);
}
}
}
Make it a private instance variable, not static.
If you need to maintain this count per user (but only for the given session), then you can do the following:
if (Session["Count"] == null)
Session["Count"] = 0;
Session["Count"] = (int)Session["Count"] + MyNewValue;
If you want the count to persist across session, then you can persist it to a database.
Static variables (and properties) will be shared amongst all instances of that type -- in this case, your controller. The value will be lost when the application pool is restarted.
If you need the value to persist across requests, for a specific user, then you may need to look to move it to the session, or similar.
If you only need the value to remain for the duration of the current request, then a private variable would suffice.
There is an important difference between class variables and object variables. Static variables are class variables, this means all objects that are instantiated from a class share the same variable, so a change of that static variable in an object changes other objects of the same class too.
But a nonstatic variable (object variable) is created for each instantiated object, so change doesnt effect others.
But the problem is not to choose between this two because your need is different. You need a variable that will be kept for each user. So as others stated, you must use a session variable.
But i think you should read about object variables and class variables.
Statics are neither good nor bad. They simply have a different usage structure.
Consider that you are processing international telephone numbers.
You will need a country_code, country and a unique id at a minimum in order to do this. You may also need to IDD country escape prefix.
So you create an object to hold all of this and then gather them into a list from say a database or some other method.
You want a drop down to list the country that the user picks and then you want the country_code to go with whatever it is that you are gathering.
If you create the list of country objects as static then when you make the round trips to and from the server you don't have to re-load the list from it's backing store everytime, you just use it to populate the drop down list. Since this data never changes it's ok to make it static. Everyone on the site will be using the same list of countries so, having one copy does not matter. However, you will have to make the Id used to index the list non static so that when you restore the selection on the list everyone has their selection and not a global static one that shows what the last person selected.
Set your models non static county_code_id to used the id selected in the list and then when you are ready to update the data use the models country_code_id to lookup the country_code in the list of country objects to return the country_code for your update.
Like I said, statics are neither good or bad, they just have a different usage.