replacement for static variable - c#

I am developing an ASP.NET MVC 4 application. userMenus is a static variable that is loaded every time a user logs in.
public class MenuCL
{
public static List<UserMenu> userMenus = new List<UserMenu>(); // the static variable
}
public class UserMenu
{
public decimal MenuID { get; set; }
public string MenuName { get; set; }
public string Controller { get; set; }
public bool Permission { get; set; }
}
I use that static variable to check whether or not the logged in user has permission to a menu/controller in a custom authorize filter.
It works fine when a single user is logged in, but when two or more users are logged-in, it's all messed up, I mean the error page("you don't have access to this page") is displayed to a user that has permission to the menu/controller.
Only now I realized it's the static variable that is causing all the trouble, after I read this :
The static variables will be shared between requests. Moreover they will be initialized when application starts, so if the AppDomain, thus application gets restarted, their values will be reinitialized.
So I need a replacement for this static variable. Anyone has any suggestion?

You can still use a static field which is a property that provides access to a session variable.
public static List<UserMenu> UserMenus
{
set
{
Session["UserMenus"] = value;
}
get
{
return Session["UserMenus"] == null ? new List<UserMenu>() : (List<UserMenu>) Session["UserMenus"];
}
}
In order to get this working on a web farm which uses a session state server (or sql server), you need to put [Serializable] attribute on top of UserMenu.
I don't think, this way you need to modify your code very much.

My question is, why do you want to use static variable? Do you want to share the values across the application? In this case you can better use session.
Updated
Assume lst as a non static List of UserMenu. Then you can use the following method to store it in session and get it bak whenever you want.
To store
Session["usemenulist"] = lst;
To get it back
try
{
lst = (List<UserMenu>)Session["usemenulist"];
}
catch
{
}
Note
If you are getting the values from the database lo load it to the List for the first time, then you can query database to get it from the database whenever you want, instead of storing it in the session. (This is another option apart from Session, you may try this way also if you want.)

Related

Best practice to store temporary information

When my user in the students Role login to the system, he can select various classes that he's enrolled. I already have a filter that'll redirect him to the select class page so he must select a class to access the system, and change it anytime he wants and the whole system's context will change.
As for now, i'm storing IdClass in the session variable, using the code below, and the system uses it to filter all the related queries and functions, like showing all the lessons from the current class. My question is: is this a good practice? Is this right or is there any better and efficient way? I'm trying to follow patterns.
[Serializable]
public sealed class Session
{
private const string SESSION_FOO = "STUDYPLATFORM_GUID";
private Session()
{
this.IdClass= 0; // Construct it to 0 so it evaluate as there's no Class selected.
}
/* This is the session's public IdClass that
i can get and set throughout the application. */
public int IdClass { get; set; }
public static Session Current
{
get
{
if (HttpContext.Current.Session[SESSION_FOO] == null)
{
HttpContext.Current.Session[SESSION_FOO] = new Session();
}
return HttpContext.Current.Session[SESSION_FOO] as Session;
}
}
}

Using a session variable in authentification within asp.net mvc 4 application

i have an asp.net mvc4 application, in which i have this class:
public class Internaute {
public int Id { get; set; }
public string Name { get; set; }
public string Login { get; set; }
public string Password { get; set; }
}
then, when a user connect, i get its informations by storing it in a session variable like this:
Session["user"] = myInternaute;
And i used these informations ,for example, like this:
#{
Internaute myInternaute = (Internaute)Session["user"];
string login = myInternaute.Login;
string pwd = myInternaute.Password;
}
I test the autorization of the user to acces by
Internaute myInternaute = (Internaute)Session["user"];
if(myInternaute == null) return RedirectToAction("Index");
So i have these questions:
Is it a good way to proceed by a session variable?
Is there another idea to do this, because the session were lost.
Does this idea have some advantages?
Thanks,
Is it a good way to proceed by a session variable?
Yes your code looks good except you should check for null whenever you get the value from Session to make sure its not null. Also, do you really need Password stored in session? Its not a good idea to store it as string in Session.
Is there another idea to do this, because the session were lost.
If I understand your question correctly, yes your session data will be lost on Session timeout. If you want you can increase the session timeout in the web.config file.
Does this idea have some advantages?
You will have some basic data about the user readily available in Session instead of querying the database but you should make sure that the Internaute class remains lightweight.

ASP.NET maintaining static variables

Recently we learned about AppDomain Recycling of IIS and how it affects static variables setting them to their primary values (nulls, 0s, etc).
We use some static variables that are initialized in a static constructor (for first time initialization, configuration values like "number of decimal places", "administrator email", etc... that are retrieved from DB) and then only read their value along the website execution.
Whats the best way of solving this problem? Some possible ideas:
Checking if variable is null/0 at each retrieval (don't like it because of a possible performance impact + time spent to add this check to each variable + code overload added to the project)
Somehow preventing AppDomain Recycling (this reset logic doesn't happen in Windows forms with static variables, shouldn't it work similarly as being the same language in both environments? At least in terms of standards as static variables management)
Using some other way of holding these variables (but we think that for being some values used for info as global reference for all users, static variables were the best option performance/coding wise)
Subscribing to an event that is triggered in those AppDomain Recycling so we can reinitialize all those variables (maybe best option if recycling can't be prevented...)
Ideas?
I would go with the approach that you don't like.
Checking if variable is null/0 at each retrieval (don't like it because of a possible performance impact + time spent to add this check to each variable + code overload added to the project)
I think it's faster than retireving from web.config.
You get a typed object
Its not a performance impact as you are not going to database on every retrieval request. You'll go to database (or any source) only when you find that current value set to its default value.
Checking the null wrapped into code:
public interface IMyConfig {
string Var1 { get; }
string Var2 { get; }
}
public class MyConfig : IMyConfig {
private string _Var1;
private string _Var2;
public string Var1 { get { return _Var1; } }
public string Var2 { get { return _Var2; } }
private static object s_SyncRoot = new object();
private static IMyConfig s_Instance;
private MyConfig() {
// load _Var1, _Var2 variables from db here
}
public static IMyConfig Instance {
get {
if (s_Instance != null) {
return s_Instance;
}
lock (s_SyncRoot) {
s_Instance = new MyConfig();
}
return s_Instance;
}
}
}
Is there any reason why you can't store these values in your web.config file and use ConfiguationManager.AppSettings to retrieve them?
ConfigurationManager.AppSettings["MySetting"] ?? "defaultvalue";
In view of your edit, why not cache the required values when they're first retrieved?
var val = HttpContext.Cache["MySetting"];
if (val == null)
{
val = // Database retrieval logic
HttpContext.Cache["MySetting"] = val;
}
It sounds like you need a write-through (or write-behind) cache, which can be done with static variables.
Whenever a user changes the value, write it back to the database. Then, whenever the AppPool is recycled (which is a normal occurrence and shouldn't be avoided), the static constructors can read the current values from the database.
One thing you'll have to consider: If you ever scale out to a web farm, you'll need to have some sort of "trigger" when a shared variable changes so the other servers on the farm can know to retrieve the new values from the server.
Comments on other parts of your question:
(don't like [Checking if variable is null/0 at each retrieval] because of a possible performance impact + time spent to add this check to each variable + code overload added to the project
If you use a write-through cache you won't need this, but in either case The time spent to check a static variable for 0 or null should be negligible.
[AppDomain recycling] doesn't happen in Windows forms with static variables, shouldn't it work similarly as being the same language in both environments?
No, WebForms and WinForms are completely different platforms with different operating models. Web sites should be able to respond to many (up to millions) of concurrent users. WinForms are built for single-user access.
've resolved this kind of issue, following a pattern similar to this. This enabled me to cater for handling circumstances where the data could change. I set up my ISiteSettingRepository in the bootstrapper. In 1 application I get the configuration from an XML file but in others I get it from the database, as and when I need it.
public class ApplicationSettings
{
public ApplicationSettings()
{
}
public ApplicationSettings(ApplicationSettings settings)
{
ApplicationName = settings.ApplicationName;
EncryptionAlgorithm = settings.EncryptionAlgorithm;
EncryptionKey = settings.EncryptionKey;
HashAlgorithm = settings.HashAlgorithm;
HashKey = settings.HashKey;
Duration = settings.Duration;
BaseUrl = settings.BaseUrl;
Id = settings.Id;
}
public string ApplicationName { get; set; }
public string EncryptionAlgorithm { get; set; }
public string EncryptionKey { get; set; }
public string HashAlgorithm { get; set; }
public string HashKey { get; set; }
public int Duration { get; set; }
public string BaseUrl { get; set; }
public Guid Id { get; set; }
}
Then a "Service" Interface to
public interface IApplicaitonSettingsService
{
ApplicationSettings Get();
}
public class ApplicationSettingsService : IApplicaitonSettingsService
{
private readonly ISiteSettingRepository _repository;
public ApplicationSettingsService(ISiteSettingRepository repository)
{
_repository = repository;
}
public ApplicationSettings Get()
{
SiteSetting setting = _repository.GetAll();
return setting;
}
}
I would take a totally different approach, one that doesn't involve anything static.
First create a class to strongly-type the configuration settings you're after:
public class MyConfig
{
int DecimalPlaces { get; set; }
string AdministratorEmail { get; set; }
//...
}
Then abstract away the persistence layer by creating some repository:
public interface IMyConfigRepository
{
MyConfig Load();
void Save(MyConfig settings);
}
The classes that can read and write these settings can then statically declare that they depend on an implementation of this repository:
public class SomeClass
{
private readonly IMyConfigRepository _repo;
public MyClass(IMyConfigRepository repo)
{
_repo = repo;
}
public void DoSomethingThatNeedsTheConfigSettings()
{
var settings = _repo.Load();
//...
}
}
Now implement the repository interface the way you want (today you want the settings in a database, tomorrow might be serializing to a .xml file, and next year using a cloud service) and the config interface as you need it.
And you're set: all you need now is a way to bind the interface to its implementation. Here's a Ninject example (written in a NinjectModule-derived class' Load method override):
Bind<IMyConfigRepository>().To<MyConfigSqlRepository>();
Then, you can just swap the implementation for a MyConfigCloudRepository or a MyConfigXmlRepository implementation when/if you ever need one.
Being an asp.net application, just make sure you wire up those dependencies in your Global.asax file (at app start-up), and then any class that has a IMyConfigRepository constructor parameter will be injected with a MyConfigSqlRepository which will give you MyConfigImplementation objects that you can load and save as you please.
If you're not using an IoC container, then you would just new up the MyConfigSqlRepository at app start-up, and manually inject the instance into the constructors of the types that need it.
The only thing with this approach, is that if you don't already have a DependencyInjection-friendly app structure, it might mean extensive refactoring - to decouple objects and eliminate the newing up of dependencies, making unit tests much easier to get focused on a single aspect, and much easier to mock-up the dependencies... among other advantages.

dealing with static list

I have create a permission object that stores userId, Groups user is in and userĀ“s permissions. This is a public class
I also need to have a static object that stores a list of those permissions objects that if a administration changes anything in the permissions all changes apply immediately for every logged user
I have a couple of questions:
Should I create this static object when the first user logs in or there is a mechanism a should use to create that list before the first user log-in (For instance when we start our app on IIS)?
Would it be easy to remove the item list for a specific user when it log-out?
This is a system requirement that permissions settings take effect as soon as the administrator make changes.
Edit 1:
public class permissionTemp
{
public static Guid userGuid { get; set; }
public static string[] grupos { get; set; }
public static string[] permissoes { get; set; }
}
public static class security
{
public List<permissionTemp> userPermissionSet { get; set; }
}
Think about a singleton, so you do not worry about creation time:
Singleton:
public class Permission
{
private Permission()
{ }
private static Permission _instance = null;
public static Permission Instance
{
get
{
if(_instance == null)
{
_instance = new Permission();
}
return _instance
}
}
Now you can have access to the same instance with
Permission.Instance
The object is created at the first access. So in the private constructor you can add your code to read the permissions fom database.
You can use the Application_Start method in the global.asax to run some code when the website starts for the first time. This will run before the first request is processed.
You can use the Session_End method in the global.asax to remove the item from the list. Also you can do it at the same time where you execute FormsAuthentication.SignOut (if you use Forms Authentication).
Note: I would use some locking mechanism to prevent multiple simultaneous access to the list. An alternative place to store the list would be in the WebCache. This is used by all users, so if it is updated by person x, next read from person y will be the updated version.
First of all i recommend to avoid creating static object for storing such sensetive information and also if any user has closed browser without clicking "Log out" then object will not be removed for that particular User.
Still if you need to do this to meet your requirement you can create it in that object in Applciation Start Event on Global.asax file when application start first time.

Static Session Class and Multiple Users

I am building a class to store User ID and User Role in a session. I'm not sure how this class will behave when multiple users are on the site at the same time. Does anyone see a problem with this?
public static class SessionHandler
{
//*** Session String Values ***********************
private static string _userID = "UserID";
private static string _userRole = "UserRole";
//*** Sets and Gets **********************************************************
public static string UserID
{
get
{
if (HttpContext.Current.Session[SessionHandler._userID] == null)
{ return string.Empty; }
else
{ return HttpContext.Current.Session[SessionHandler._userID].ToString(); }
}
set
{ HttpContext.Current.Session[SessionHandler._userID] = value; }
}
public static string UserRole
{
get
{
if (HttpContext.Current.Session[SessionHandler._userRole] == null)
{ return string.Empty; }
else
{ return HttpContext.Current.Session[SessionHandler._userRole].ToString(); }
}
set
{ HttpContext.Current.Session[SessionHandler._userRole] = value; }
}
}
The code you posted is the exact replica of some code we have here.
It has been working fine for 2 years now.
Each users access is own session. Every request made to the server is a new thread. Even though 2 request are simultaneous, the HttpContext.Current is different for each of those request.
You'll get a new session for each connection. No two users will ever share session. Each connection will have its own SessionID value. As long as the user stays on your page (doesn't close the browser, etc.) the user will retain that session from one request to the next.
This will work fine for mutiple users accessing your application as there will be different sessionid generated for all deffrent users accessing application concurrentely. It will work in similar way if you have defined two different session variables in your system.
It will be like wrapping tow session states using static wrapper class SessionHandler.

Categories

Resources