Maintaining session in a class C# - c#

I am trying to maintain session in a class for MVC application. Below is the code which i used get and set session in a variable. But whenever i am accessing this variable after set, it is giving null.
public static class MySession
{
public static string MyVar
{
get
{
return HttpContext.Current.Session["MyVar"] == null ? "" : HttpContext.Current.Session["MyVar"].ToString();
}
set
{
HttpContext.Current.Session["MyVar"] = value;
}
}
}
And I used to set as
MySession.MyVar="testData";
But when i access
string str = MySession.MyVar;
it gives null value. Does anybody know why my session is not stored?

Session variables are very much exposed to being null, that is each time a new session is created by user, browser, network or application itself. That is why, it is very much recommended to wrap it around with if...else block.
if(Session["key"] != null) {
// Variable exists for the session
// use variable
} else {
// Variable doesn't exist in the session
// create and user variable
}
However, if still you always get a null, then you should check what is going wrong. My bet is that there is some other code or process that terminates the previous sessions and restarts them. You should know you can programmatically also remove all sessions, that might also cause this problem.
Also, Session variables can be used and served using a class, there is no problem in that. Just make sure that the collection Session isn't being refreshed.

My guess is you have not enabled session state.
<system.web>
<sessionState mode="InProc" timeout="60"/>
<system.web>
Session state is disabled by default in MVC and is generally not recommended unless absolutely necessary.

Related

Cache gets null when I try to retrieve information in another class method

I'm trying to use cache to save some information for later use. This is how I assign cache:
foreach(MibGet Device in DeviceValuesList)
{
if (HttpContext.Current.Cache[DeviceID] == null)
{
HttpContext.Current.Cache[DeviceID] = DeviceValue;
}
}
I can see in the debugger that this code works absolutely fine, all the data I want is assigned properly. But when I try to retrieve this information from the cache like this (From another class method):
if (NewValue != HttpContext.Current.Cache[DeviceID].ToString())
{
HttpContext.Current.Cache[DeviceID] = NewValue;
}
It throws a null reference exception. In the debugger It show that HttpContext.Current is null. What could be the problem and how can I solve this?
HttpContext.Current is null when there is no current HttpContext. ASP.NET uses one thread per request model. It creates an instance of HttpContext and associates it to the thread that process the request. But if you create a thread, explicitly o implicitly by using tasks or async programming, it might not be associated with an HttpContext
I suggest you using some other cache classes such as System.Runtime.Caching.MemoryCache that are not tied to an HttpContext.
I'm assuming your cache is a dictionary. Then instead of
if (get.Value != HttpContext.Current.Cache[get.DeviceID.ToString()].ToString())
you should write
if (!HttpContext.Current.Cache.ContainsKey(get.DeviceID))
Also in your first code snippet you put Device.Value in the cache, but in the second snippet you put DeviceID. I can't see how that'd work.

Why Session End is called on App Start up?

I wanna free some DB resources and set few flags when User Session Ends in ASP.NET Site. But when I write my code to access session variables in Session End method of Global.asax file, its getting called everytime the App starts, Why this weird behavior?
Secondly, I want to access user specific session variables and free them up in DB on Session End. Thus I am using few session Variables where I am setting them in a webmethod on a Page and trying to access them on Session End. But since Session end is being called on App start up its always throws Null reference exception.
Here is mycode. for Setting up a variable in Webmethod in a .aspx page
[WebMethod(EnableSession=true)]
protected void checkUser()
{
Session["TestObject"] = "Hello I am session";
}
In my global.asax file I am trying to access as follows in Session_End method
void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.
if (this.Context.Session != null && this.Context != null)
{
string k = this.Session["TestObject"].ToString();
}
}
I even tried HttpContext.current.Session etc.. but none worked. All are throwing exception as Session end is called on App start up and even when session timed out.

ASP.NET HttpResponse Cookies null check

I have a null check in code that is checking to see whether a cookie exists in the response object already:
if (HttpContext.Current.Response.Cookies["CookieName"] != null)
{
sessionCookie = HttpContext.Current.Response.Cookies["CookieName"];
cookieValue = sessionCookie.Value;
}
When I check through the debugger the key doesn't exist before the check, but it does exists after the check. Thus the return value from the cookie is null. Does checking for a cookies existence automatically create the cookie?
Thanks in advance
That case, when the first answer contains a nonsense not related to the question.
Every time when you do the check:
if (HttpContext.Current.Response.Cookies["CookieName"] != null)
this line of code not only checks, whether a cookie exists, but also creates a new empty cookie. Even Get method creates[1] the new cookie implicitly.
You can use the code like this:
Cookie existing_cookie = null;
foreach (Cookie c in HttpContext.Current.Response.Cookies)
{
if ("CookieName" == c.Name)
{
existing_cookie = c;
break;
}
}
if (null != existing_cookie)
{
// exists
}
Or use LINQ methods to do almost the same.
The answer is yes, calling Response.Cookies["CookieName"] in any manner actually creates the cookie.
This happens because HttpContext.Current is associated with the thread that the request is currently executing on. On a different thread, the framework has no way to know which request you want to use.
There are ways to fix this-- for example .NET's BackgroundWorker can propagate context to another thread. The Asynchronous Pages support in ASP.NET will also propagate context correctly.
So you have two options: either rewrite all your async code to use context-passing async mechanisms like BackgroundWorker or Async Pages, or change your code to check for HttpContext.Current==null before trying to access any properties of HttpContext.Current

FormsAuthentication.RedirectToLoginPage() does nothing

I have the following problem: republishing ASP.NET web app causes (as expected) session resetting where I keep additional user info (what on access attempt will cause NullReferenceException).
To avoid that, my page checks this info existence and in case of null redirects user to the login page (forms auth), so I'm calling:
void LogOut()
{
Session.Clear();
Session.Abandon();
User = null;
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage()
}
But sometimes it doesn't help, so I found a workaround:
Response.Redirect(FormsAuthentication.LoginUrl);
but it doesn't add returnUrl, what I wish it were (I don't want to emulate this behavior manually).
So want to figure out why does the first way doesn't work as expected.
Have you tried calling Response.End() after FormsAuthentication.RedirectToLoginPage() ?
I have the following problem: republishing ASP.NET web app causes (as expected) session resetting where I keep additional user info (what on access attempt will cause NullReferenceException).
But sometimes it doesn't help
I'm not sure what you mean by "sometimes it doesn't help" - you don't say what exactly happens.
But you should remember that expiration of a Forms Authentication ticket and expiration of a Session timeout are completely independent. A user's session can timeout while his Forms Authentication ticket is still valid and vice versa.
In general, when accessing data from Session, you should always test for existence first, and refresh it if necessary:
object o = Session["Whatever"];
if (o == null)
{
o = ... refresh it e.g. from the database
Session["Whatever"] = o;
}
...
Often it's useful to use a helper class to encapsulate this.
In your case you refer to "additional user info" - so you'll probably be able to retrieve this using HttpContext.Current.User.Identity.Name as a key.
Forcing a user to log in again because a Session has expired, e.g. because of an Application Pool recycle on the server, is very unfriendly.
UPDATE
The MSDN documentation for RedirectToLoginPage states that:
Unlike the HttpResponse.Redirect method, this method does not end the request by calling HttpResponse.End. This means that code that follows the RedirectToLoginPage method call will run.
This probably explains what you're seeing: code in the Page life cycle after your call to RedirectToLoginPage is running, and throwing a NullReferenceException.
You could call Response.End after RedirectToLoginPage to avoid this.
My Session timeout set = Forms auth timeout (via web.config).
I would re-iterate that Session expiry and FormsAuthentication expiry are unrelated, even if the timeouts happen to be the same. A FormsAuthentication cookie will survive an application pool recycle on the server; a Session will not.

Is there something like SESSION in Windows application?

Is there something like SESSION in Windows application? I want to store a few values to be persistent between forms.
For example: First form has some check boxes and third form process them accordingly. So I need to store the checked checkboxes somewhere.
If you're talking about different Forms within the same Application, then just create some static members on a class, it will be persisted for the lifetime of the executable.
You could only expose your CheckBoxes Checked state through properties of this form where you put your CheckBoxes on, and access these properties from your third or Process form.
public partial class MainForm : Form {
// We assume we have let's say three CheckBoxes named chkFirst, chkSecond and chkThird
public bool IsFirstChecked { get { return chkFirst.Checked; } }
public bool IsSecondChecked { get { return chkSecond.Checked; } }
public bool IsThirdChecked { get { return chkThird.Checked; } }
// Calling this form from where these checked states will be processed...
// Let's suppose we have to click a button to launch the process, for instance...
private void btnLaunchProcess(object sender, EventArgs e) {
ProcessForm f = new ProcessForm();
f.Parent = this;
if (DialogResult.OK == f.ShowDialog()) {
// Process accordingly if desired, otherwise let it blank...
}
}
}
public partial class ProcessForm : Form {
// Accessing the checked state of CheckBoxes
private void Process() {
if ((this.Parent as MainForm).FirstChecked)
// Process according to first CheckBox.Checked state.
else if ((this.Parent as MainForm).SecondChecked)
// Process according to second CheckBox.Checked state.
else if ((this.Parent as MainForm).ThirdChecked)
// Process according to third CheckBox.Checked state.
}
}
Please consider that I picked this code up the top of my head, so it might happen not to compile. Anyway, I hope that this gives you an idea of how to pass your values throughout your forms.
The biggest difference between Web and WinForm programming is that Web is stateless. SESSION and VIEWSTATE are workarounds to allow one to preserve values.
WinForms are stateful, so you don't need to go through SESSION and VIEWSTATE-like variables. A value is preserved as long as the object exists.
You can use app.config (or Settings section in Project's Properties) if you use Visual Studio, or just serialize your values and store them in some file.
If you want to persist data between independent execution of the same app (as in concurrent request serving in a HTTP farm) then just write out some XML or use a mashalling/serializing system with your runtime/plaform (dunno what it would be for C#).
Then import it again. Just watch your concurrency control.
If this is just a regular single-user windows application, create a class to model the state you want to pass around and require it in your form constructors:
internal class ApplicationState
{
// Store the selected checkbox values here, for example
public List<int> SelectedProductIds { get; }
// ... additional state ...
}
internal class EditOrderForm: Form
{
private ApplicationState applicationState;
public EditCustomerForm(ApplicationState applicationState) {
this.applicationState = applicationState;
}
// Rest of the code
}
You could use static variables instead of instances - but those are just global variables that make your code harder to read and maintain.
If you are looking to store data on a per user basis between execution sessions, you should consider Isolated Storage.
Doesn't clutter install directory
Doesn't cause issues with AnitVirus software
Part of the OS including .Net objects, don't need to install anything else
Already works with the Windows security model
Exists on a per user basis, so saved settings are separated for each user
Can serialize/deserialize obects directly into it

Categories

Resources