How to access session variables from any class in ASP.NET? - c#

I have created a class file in the App_Code folder in my application. I have a session variable
Session["loginId"]
I want to access this session variables in my class, but when I am writing the following line then it gives error
Session["loginId"]
Can anyone tell me how to access session variables within a class which is created in app_code folder in ASP.NET 2.0 (C#)

(Updated for completeness)
You can access session variables from any page or control using Session["loginId"] and from any class (e.g. from inside a class library), using System.Web.HttpContext.Current.Session["loginId"].
But please read on for my original answer...
I always use a wrapper class around the ASP.NET session to simplify access to session variables:
public class MySession
{
// private constructor
private MySession()
{
Property1 = "default value";
}
// Gets the current session.
public static MySession Current
{
get
{
MySession session =
(MySession)HttpContext.Current.Session["__MySession__"];
if (session == null)
{
session = new MySession();
HttpContext.Current.Session["__MySession__"] = session;
}
return session;
}
}
// **** add your session properties here, e.g like this:
public string Property1 { get; set; }
public DateTime MyDate { get; set; }
public int LoginId { get; set; }
}
This class stores one instance of itself in the ASP.NET session and allows you to access your session properties in a type-safe way from any class, e.g like this:
int loginId = MySession.Current.LoginId;
string property1 = MySession.Current.Property1;
MySession.Current.Property1 = newValue;
DateTime myDate = MySession.Current.MyDate;
MySession.Current.MyDate = DateTime.Now;
This approach has several advantages:
it saves you from a lot of type-casting
you don't have to use hard-coded session keys throughout your application (e.g. Session["loginId"]
you can document your session items by adding XML doc comments on the properties of MySession
you can initialize your session variables with default values (e.g. assuring they are not null)

Access the Session via the thread's HttpContext:-
HttpContext.Current.Session["loginId"]

The problem with the solution suggested is that it can break some performance features built into the SessionState if you are using an out-of-process session storage. (either "State Server Mode" or "SQL Server Mode"). In oop modes the session data needs to be serialized at the end of the page request and deserialized at the beginning of the page request, which can be costly. To improve the performance the SessionState attempts to only deserialize what is needed by only deserialize variable when it is accessed the first time, and it only re-serializes and replaces variable which were changed. If you have alot of session variable and shove them all into one class essentially everything in your session will be deserialized on every page request that uses session and everything will need to be serialized again even if only 1 property changed becuase the class changed. Just something to consider if your using alot of session and an oop mode.

The answers presented before mine provide apt solutions to the problem, however, I feel that it is important to understand why this error results:
The Session property of the Page returns an instance of type HttpSessionState relative to that particular request. Page.Session is actually equivalent to calling Page.Context.Session.
MSDN explains how this is possible:
Because ASP.NET pages contain a default reference to the System.Web namespace (which contains the HttpContext class), you can reference the members of HttpContext on an .aspx page without the fully qualified class reference to HttpContext.
However, When you try to access this property within a class in App_Code, the property will not be available to you unless your class derives from the Page Class.
My solution to this oft-encountered scenario is that I never pass page objects to classes. I would rather extract the required objects from the page Session and pass them to the Class in the form of a name-value collection / Array / List, depending on the case.

In asp.net core this works differerently:
public class SomeOtherClass
{
private readonly IHttpContextAccessor _httpContextAccessor;
private ISession _session => _httpContextAccessor.HttpContext.Session;
public SomeOtherClass(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void TestSet()
{
_session.SetString("Test", "Ben Rules!");
}
public void TestGet()
{
var message = _session.GetString("Test");
}
}
Source: https://benjii.me/2016/07/using-sessions-and-httpcontext-in-aspnetcore-and-mvc-core/

I had the same error, because I was trying to manipulate session variables inside a custom Session class.
I had to pass the current context (system.web.httpcontext.current) into the class, and then everything worked out fine.
MA

This should be more efficient both for the application and also for the developer.
Add the following class to your web project:
/// <summary>
/// This holds all of the session variables for the site.
/// </summary>
public class SessionCentralized
{
protected internal static void Save<T>(string sessionName, T value)
{
HttpContext.Current.Session[sessionName] = value;
}
protected internal static T Get<T>(string sessionName)
{
return (T)HttpContext.Current.Session[sessionName];
}
public static int? WhatEverSessionVariableYouWantToHold
{
get
{
return Get<int?>(nameof(WhatEverSessionVariableYouWantToHold));
}
set
{
Save(nameof(WhatEverSessionVariableYouWantToHold), value);
}
}
}
Here is the implementation:
SessionCentralized.WhatEverSessionVariableYouWantToHold = id;

Related

How to combine database access and cache in asp.net mvc (An object reference is required for the non-static field, method, or property 'Module.dbApp')

This is actually 2 questions in one.
I have an asp.net mvc application where I have to load a list of Modules, its just a simple list with ID, modulename and a class name to render it on the view with font awesome.
My model is like this:
public class Module
{
[Key]
public int Id { get; set; }
public string ModuleName { get; set; }
public string FontAwesomeClass { get; set; }
}
Because the module list is a Partial View that will render some icons on the top navigation bar, I dont want that for each refresh of the app, it goes to the DB, so it must be cached(I am using Azure REDIS Cache, not relevant for the question anyway), so instead of calling the DB context directly from the controller, I am calling a Cache Class that will check if the cache object exists, if not it will retrieve it from DB, if it does, it will return it from cache.
This my solution structure:
http://screencast.com/t/uayPYiHaPCav
Here is my controller Module.cs
public ActionResult GetModules()
{
return View(Cache.Module.GetModules());
}
As you can see the Controller does not have any logic where to get the data from.
Here is the Module.cs (on the Cache Namespace)
public class Module
{
private AppDataContext dbApp = new AppDataContext();
//Load modules from cache or from database
public static List<Models.Module> GetModules()
{
IDatabase cache = Helper.Connection.GetDatabase();
List<Models.Module> listOfModules = (List<Models.Module>)cache.Get("Modules");
if (listOfModules == null)
{
return dbApp.ModuleList.ToList();
}
else
{
return listOfModules;
}
}
}
Here I have a compiler error which I am not sure how to best fix it:
Error CS0120 An object reference is required for the non-static field,
method, or property 'Module.dbApp'
So that was my first question.
The 2nd question is more about the design pattern, do you consider this correct or not? the way I am trying to get the data from Cache, and its actually the Cache class which checks if data is on it or if it has to go to the DB.
First Question: make your private member static
private static AppDataContext dbApp = new AppDataContext();
2nd Question: your cache strategy seems pretty standard. The only thing is that you might want to expire cache data. For example, the cached data can get old and the longer it stays in the cache the older it gets. You might at some point want to expire it and get fresh data again.
Update:
#EstebanV for code sample (this off the top of my head, don't assume that it compiles):
/**
ICachedPersonDao abstracts away the caching mechanism
away from the core of your application
**/
public CachedPersonDao : ICachedPersonDao
{
private IPersonDao personDao = null;
public CachedPersonDao(IPersonDao personDao)
{
this.personDao = personDao;
}
public Person GetPersonById(int id){
bool isInCache = CACHE.SomeFunctionThatChecksInYourCache(id);
if (isInCache)
{
return CACHE.SomeFunctionThatReturnsTheCachedPerson(id);
}
else
{
//Well it's not in the cache so let's get it from the DB.
return this.personDao.GetPersonById(id);
}
}
}
/**
IPersonDao abstracts database communication
away from the core of your application
**/
public class PersonDao : IPersonDao
{
public Person GetPersonById(int id)
{
/** Get the person by id from the DB
through EntityFramework or whatever
**/
}
}
Usage:
In your controller, use ICachedPersonDao if you want to attempt to get from cache or use IPersonDao if you want to get it directly from the database without checking the cache.
Like I said, you should learn Dependency Injection it will help "inject" these dependencies into the classes that uses them.
I say again, this is off the top of my head. It won't compile. It's just to illustrate the concept.

Global class variable for ASP.NET

I am building an ASP.NET Application which has 2 projects.
One is a class library having BL Code.
I want to create a public class instance variable from one of the classes in BL.
This class instance variable is to avoid loading all the data on each request which makes my application to respond slow for each request.
How to make the global class variable load data at page_Load, and keep it until the user redirects to another page.
Create it in ViewState and wrap it in a property for easy of use. Something along the lines of:
public MyClass MyObj {
get {
if (ViewState["MyObj"] == null){
ViewState["MyObj"] = new MyClass();
}
return ViewState["MyObj"];
}
set {
ViewState["MyObj"] = value;
}
}

How can I store static class objects for recall on any page?

I want to store static values in a class for later use use on any page in the web. The values will be the same for all users.
Page_Init: Retrieve global variables from their respective sources and assign them to their static objects inside the classes within the GlobalStaticVariables class.
I call to set the static values from the MasterPage like so
protected void Page_Init(object sender, EventArgs e)
{
Web.StartUp.SetGlobalStaticVariables(this.Page);
}
///Removed most objects for the sake of brevity
public static Info.GlobalStaticVariables SetGlobalStaticVariables(object _this)
{
Info.GlobalStaticVariables.Some_StringValue = ConfigurationManager.AppSettings["Some_StringValue"].ToString();
Info.GlobalStaticVariables.Database.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ToString();
Info.GlobalStaticVariables.IIS.DomainName = ((Page)_this).Request.Url.Host;
}
///Removed most objects for the sake of brevity
public class Info
{
public class GlobalStaticVariables
{
public static string Some_StringValue { get; set; }
public class Database
{
public static string ConnectionString { get; set; }
}
public class Ldap
{
public static List<string> ServerList { get; set; }
}
}
}
I thought that I should first see if the Session object exists, then create if it doesn't as I have read that sometimes static values can be lost due to appPool recycle, etc.
I figured I should do this from the MasterPage since I have to reference "Session" but I don't know how I would pass the Page object to a property in a class file.
I use the following in the MasterPage to store the current user so I thought that I could do a similar thing with global variables. So far I have been unsuccessful.
public MyClass.Users.CurrentUser GetSetCurrentUser
{
get
{
if (Session["CurrentUser"] == null) GetSetCurrentUser = new MyClass.Users.CurrentUser();
return (MyClass.Users.CurrentUser)Session["CurrentUser"];
}
set { Session.Add("CurrentUser", value); }
}
With the previous though, I also have to add the following to each page that wants to reference the GetSetCurrentUser property (Master.GetSetCurrentUser ), but I would prefer to avoid this if possible.
<%# MasterType VirtualPath="~/mp.Master" %>
Unfortunately when I tried the same with GlobalStaticVariables no intellisense appeared aside from .Equals, .GetHashCode, .GetType and .ToString.
I want to be able to call the property GlobalStaticVariables from any page for easy access to it's static values.
Perhaps my thought process is flawed in attempting to do it this way, but I can't think of another way. Perhaps I needs to step away from this for awhile and enjoy the holiday, but I can't, I'm on a mission. :-)
Thank-you for you time and suggestions.
You're looking for HttpApplicationState that is available in your page by Context property which holds an Application property.
How you can use it:
void Page_Load(object sender, EventArgs e)
{
var last = Context.Application["lastActivity"];
lblLastActivity.Text = last == null?"(none)": ((DateTime) last).ToString();
Context.Application["lastActivity"] = DateTime.Now;
}
One other option is the use of Cache which works similar but objects stored in the Cache can get removed from the cache (to free memory). You should be able to reload the objects in that case though.

replacement for static variable

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.)

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.

Categories

Resources