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.
Related
I have seen many "wrapper" classes for the ASP.NET Session state and some do something like:
Strongly Typed Layer (Pseudo Code #1)
public class MySession
{
public int MyID
{
get
{
return Convert.ToInt32(HttpContext.Current.Session["MyID"]);
}
set
{
HttpContext.Current.Session["MyID"] = value;
}
}
public string MyName
{
get
{
return (HttpContext.Current.Session["MyName"]).ToString();
}
set
{
HttpContext.Current.Session["MyName"] = value;
}
}
...
public MySession()
{
// Could be static or instantiated depending on needs...
}
...
}
///// USAGE IN OTHER CLASS /////
MySession currSession = new MySession();
currSession.MyID = 5;
currSession.MyName = "John Doe";
Console.WriteLine($"{currSession.MyName}'s ID = {currSession.MyID}");
Then I have seen others do something like:
Generic List Variant (Pseudo Code #2)
public class SessionVariables
{
public int MyID
{
get;
set
{
MyID = value;
MySession.SaveVariables();
}
}
public string MyName
{
get;
set
{
MyName = value;
MySession.SaveVariables();
}
}
...
}
public class MySession
{
public static List<SessionVariables> Variables;
// Might be private in real application environment
public MySession() // Could be static or instantiated depending on needs...
{
if (HttpContext.Current.Session["MyVariables"] == null)
{
HttpContext.Current.Session["MyVariables"] = new List<SessionVariables>();
}
// Obviously more appropriate checking to do here, but for simplicity's sake...
Variables = (List<SessionVariables>)HttpContext.Current.Session["MyVariables"]
}
public static void SaveVariables()
{
HttpContext.Current.Session["MyVariables"] = Variables;
}
...
}
///// USAGE /////
public class MyPage
{
public void MyMethod()
{
MySession currSession = new MySession(); // Create variables
MySession.Variables.MyID = 5;
MySession.Variables.MyName = "John Doe";
Console.WriteLine($"{MySession.Variables.MyName}'s ID = {MySession.Variables.MyID}");
...
}
}
Thoughts
Obviously, these examples are both pseudo code style (so please ignore general errors), but they illustrate some of the approaches to building a data access layer for the Session state.
I do something similar to the first variant, albeit, with a more comprehensive data type mapping/conversion plan. I use a an "normal" class to wrap Session in, but it could easily be static since the properties will pull from the Session state when their "get" is called and thus never be out of sync since the class actually doesn't hold any data itself.
The second seems more "overkill" to me from first impressions since yes, you are only storing one variable in the Session state, but it clutters up the rest of the code by forcing code to be making references to the list:
myObject.TheList.VariableIWant
VS
myObject.VariableIWant
of which I prefer the later (just looks cleaner), though this could easily be hidden in a super class or just making a local variable directly reference the list:
new MySession(); // Create the variables
List<SessionVariables> mySession = MySession.Variables;
... though that looks kind of dirty to me at first glance. However, I don't know how much of a benefit using a list for storage actually gives to code/performance since storing an object that represents a list should take as much memory as doing each variable separately, at least that is my thinking.
Question
Which is better practice / low maintenance in the long-term? And/or Which gives better performance to the website?
Option #1 is the most common pattern that I see, and I use it. You can improve it by using constants instead of magic strings. Sessions have their issues, but so does making a completely stateless app. I also recommend using HttpCache instead of Session -- it will not consume AppPool resources. But only Sessions can be used on a web farm, as long as you use a Session provider like SQL Server. Distributed caching is another matter.
With option 1 it's really easy to tell what it's doing. You're trying to standardize how your classes save/retrieve session data rather than scattering it all over the place.
Option 2 is a lot more confusing. In fact I've looked it over a few times and I can't figure what's going on the list. Why does option 2 require a list when option 1 doesn't?
For what you're trying to do, option 1 works just fine. The constants aren't a bad idea, but in this one case I might skip it. The meaning of the string is pretty obvious, and other classes won't need to duplicate it because they're going through this one to access Session.
Option #1 > Option #2
Two reasons:
You should be deleting session variables as soon as you are done with them, using Session.Remove. Otherwise your session state will keep getting bigger and bigger and your web server won't be able to support as many simultaneous users. But if all your variables are held in one big session variable, this is a bit harder to accomplish.
I would avoid using reference types (e.g. a List of any kind) in session. It creates an ambiguity: if your session is stored in-proc, the session is only storing a pointer, and you can change session variables by changing the objects that they reference just like normal reference types. But if your session is out of proc (e.g. using state server or SQL state) then your objects will be serialized and frozen, and if you change the objects that are referenced, those changes will not get reflected in your session variables. This could create all sorts of bugs that only appear on your upper environments (if your dev systems lack a state server) and drive you mad trying to troubleshoot.
You could possibly make an exception for immutable reference types, but you'd have to be careful; just because an object is immutable doesn't mean the objects that it references are immutable too.
I'm going to ftech list of my application admins(users with role 'admin') and store them in a List<ApplicationUser> AdminList inside a controller of a custom model and in its create action. AdminList is populated inside create action to populate a drop-down in create view.
I want to know is it possible that the list i.e. AdminList will be disposed among calling create and its postback? In other words, is it required to populate AdminList again inside postback method or dispose will never happen?
HTTP is stateless.
Unlike things like WPF applications or Winfows Forms applications, web applications don't maintain a "running application" filled with in-memory state. (At least not in the same intuitive way.) Each request builds up a new state each time. This includes, in the case of MVC, a new instance of the Controller. (Or in the case of Web Forms, a new instance of the Page.)
In order for the data to be persisted from one request to another, you'd need to persist it somewhere. "Somewhere" could be a whole host of different places. The page's form elements, cookies, session, static variables, a database, a file, etc.
For example, if this "admin list" is relatively static and unlikely to change, and is the same for all users of the site, then you might store it in a static property which gets lazy-loaded if it's not set. Something structurally like this:
private static List<ApplicationUser> _adminList;
private static List<ApplicationUser> AdminList
{
get
{
if (_adminList == null)
_adminList = GetAdminsFromData();
return _adminList;
}
}
(However you populate the list would be what that function call does, of course.)
That way the consuming code never really needs to know or care if the list has been populated or not. Just consume the AdminList property and, if it hasn't been populated (if for whatever reason the static context has been cleared, such as an application re-start) then it'll be populated. Otherwise it'll just contain whatever was last put there.
I need to know if it's heavier or a bad practice if i use the variable id i'm passing via request to an Action in a Controller or use the Model's IdFoo i retrieved using the same id i once passed via the same request.
Let's suppose i'm using ASP.NET MVC4 with C# and Entity Framework, and i have this Model with it's Data Annotation, declaring IdFoo as the Primary Key for the Model:
public class Foo
{
[Key]
public int IdFoo { get; set; }
}
In my FooController, in the Edit action, i need to retrieve the IdFoo, but it's the same as the id variable i'm passing via route.
public class Foo
{
[HttpGet]
public ActionResult Create(int id = 0)
{
var Foo = db.Foo.Find(id);
// Other operations.
var Bar = Foo.IdFoo;
var Qux = id;
// Bar = Qux
...
return View(Foo);
}
}
Is it a good practice/less performance intense to still keep using the id variable i'm passing via the request for the rest of the controller code, or should i use Foo.IdFoo for it? Note that Foo.IdFoo and id will always have the same value, so i know i can use both, i'm just looking for good practices or performance reasons to justify the use of one or another.
Unless IdFoo is doing something it shouldn't, it should make no difference whatsoever from a performance point of view.
From a micro-optimization stand point, I imagine it would technically be faster to use a variable that's already in the context rather than pulling it from the Foo object; but that's really splitting hairs and I have no benchmarking statistics to prove that theory.
I don't think there's any difference in performance. However, there are two other considerations:
What if the variable or the property is modified? A thousand commits later, one of this operations might end up changing the Id of that object. Or may be this won't be any of these operations, but something in the other thread. So, in case of this (now unlikely) behavior it would possibly be better to use the property. By the way, I don't know the specifics of ASP.NET, but your ID property looks like it's not supposed to change over the lifetime of the project, so it would probably be wise to make this property read-only (without an accessor), so it would only be set in constructor.
What is more readable? Right now both options look the same, but in the real world these class names often get long, so simple id would probably be better.
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; }
}