OK so to set and read variables from the current session
String Myvar =(string) System.Web.HttpContext.Current.Session[“MyVariable”]
To set
System.Web.HttpContext.Current.Session[“MyVariable”] = “NewValue”
I can do neither, I get a System.NullReferenceException: Object reference not set to an instance of an object. from System.Web.HttpContext.Current.Session.
In my web.config I have
<sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424" cookieless="false" timeout="20">
</sessionState>
I have read a dozen articles on the the necessity of IHttpHandler and an IRequiresSessionState interface. I think the issue may be caused because I am requesting this information in Page_PreInit. I found a solution in a stack overflow article but I don't seem be using it properly to actually make this go.
I am not sure what I am missing. Thanks in advance.
As the comment mentioned, is there some reason you need this in the PreInit event?
PreInit happens very early in the page lifecycle. It happens, in fact, before even the master page (if any) is applied, before all the controls are fully initialized, etc.
A much better choice for the majority of applications is in the Load event. If you're still getting a NullReferenceException there, then there's a bigger issue.
You can access the session by implementing IRequiresSessionState interface in your class.
This is a flag interface, so you dont need to implement any extra code.
When you implement this asp.net will know that you want to access the session.
public partial class YOUR_ASPX: System.Web.UI.Page , IRequiresSessionState
{
... your code
}
To access the session state pre-init you can do something like this. I use it so that I can have a different admin master than the regular user one. Each page has a method at the top.
PageTools tools = new PageTools();
protected void Page_PreInit(object sender, EventArgs e)
{
tools.setMasterPage(Page, Context);
}
PageTools is my class that holds the method that chooses the appropriate mater page and has the http handler.
public void setMasterPage(Page page, HttpContext context)
/***********************************************************************
* Author Daniel Tweddell
* Date 9/18/09
*
* Several of the pages are for non-admin use, however these pages will
* also be used by the admin users and will need to have the admin menu
* and such. So based on the login, we either show the page with the
* standard master or if the user is admin, use the admin master.
***********************************************************************/
{
if (context.Handler is IReadOnlySessionState || context.Handler is IRequiresSessionState)
{
context.Handler = Handler();
}
String sMasterPage="~/content/page.master";
if (userinfo.IsUserAdmin) sMasterPage="~/content/administrator/admin.master";//make sure the user is admin
page.MasterPageFile = sMasterPage;
}
Here is a step by step to setting up the httphandler. (which is the other thing you'll need.
Related
I'm writing an ASP.NET C# web site that needs to access data from a database and show it to the user for viewing and editing. The specific data it accesses is based on the user who logs in, and I need for multiple users to be able to use the site simultaneously, viewing and editing different data as they do so. I stumbled upon the concept of Session States, and after a lot of reading and not as much understanding. I've come across a problem.
In my default page, I do this to create a Session variable:
Session.Add("UserData",userdata);
I have also tried this:
Session["UserData"] = userdata;
Then in a later page, I do this to try to call it:
object myobject = Session["UserData"];
This gives me an error, saying that Session["UserData"] is not set to an instance of an object. This is the method everyone seems to be using, is there something I'm missing?
My site is configured on IIS to have the Session State Mode set to "In Process", but most people seem to set this manually using their web.config file. However, when I try to do this in my web.config file I am always greeted with "unrecognized configuration section". My compiler doesn't know what this is:
<sessionstate mode="inproc"/>
EDIT, more detailed code:
MyClass userdata = new MyClass();
userdata.name = "myname";
userdata.number = 5;
Session["UserData"] = userdata;
later...
MyClass mydata = (MyClass)(Session["UserData"]);
This returns the error that Session["UserData"] is null.
The fact that you can't set the session mode in the web.config is a red flag to me of something weird and smelly going on. So ...
Check that the session mode is under the system.web element of the web.config otherwise it won't be valid.
Check that enableSessionState hasn't been set to false in either the web.config or the page directive
Try to rule out IIS. If possible convert your website to a web app and run through visual studio so it starts with it's own built in web server. What happens then? Is the Session state back?
It should n't make a difference but if you are not doing the test in Page_Load then just try it there - just in case you are doing these tests somewhere unusual.
Whatever the answer is to this when we know it will be headachingly obvious. I'm geninuely looking forward to finding out what it is. Good luck
Session variables are good to manage multiple users on your website, but to initialize them you should use the Global.asax file in your web application. This file has two methods specifically for Session variables, Session_Start and Session_End. To initialize your Session variable you would use code liked the following in Global.asax:
void Session_Start(object sender, EventArgs e)
{
// initialize session variable
Session["MySessionVar"] = 1;
}
Also you may have to cast the value of your session variable if you are doing operations on it like +, for example if you have a session variable holding an integer value, you may have to do like the following:
Session["MySessionVar"] = ((int) Session["MySessionVar]) + 1;
Also, if you try to use your session variable outside of a method like Page_Load or other method, like trying to use it as a property of the System.Web.UI.Page class in your C# code behind file, that may not work, you can only use your session variables within a method.
I would search for any calls to Session.Clear or Session.Abandon to see if your session is being purged in between those two actions.
You could also hook up to the Session_End event and see if that gets hit sometime in between the two calls.
Where you have
Session.Add("UserData",userdata);
you want to check the value you need to cast the object with (string) like this
string userdata= (string)(Session["UserData"]);
you could then run a check to see
if(string.IsNullOrEmpty(userdata))
but not sure how you are initializing and assigning a a value to userdata
Does it complain the your myobject is null or that Session is null? When you try to retrieve the value you are doing this from the method of what class?
Yet another question - by any chance are you trying to access it in a parallel thread?
Hey there, I have my own Membership-Provider where I open a NHibernate-Session in the constructor:
public class OwnMembershipProvider : MembershipProvider
{
protected NHibernate.ISession HibSession;
public OwnMembershipProvider ()
{
HibSession = NHibernateTools.OpenSession();
}
//...
I figured out if I set a breakpoint into the constructor, it is called only once during application start. This gives me a headache since the same NHibernate-Session is used for each request, leading to funny things like "oh, i can't change my password" (the NHibernate-Session returns a cached user when calling ValidateUser(), which still contains the old password).
How can I force the framework to reconstruct the MemberShipProvider for each single request? Or how should it be done different?
Thx for any tipps
Opening a separate session in each method sounds like a good idea. Better yet, open one session and transaction for each HTTP request and then commit the transaction when request ends.
I have a web app with loads of pages and most of them require some session variables in order to function.
i want to put some defensive code in my app. where is the best place to put somethign like:
if (Session.Count == 0){
Response.Redirect("~/default.aspx");
}
EDIT: how do i check if the current page is defult.aspx?
Quite difficult, yeah fortunately it is solved.
You need to implement Application_PreRequestHandlerExecute in Global.asax
here is the code
/// <summary>
/// The event occurs just after Initialization of Session, and before Page_Init event
/// </summary>
protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
// here it checks if session is reuired, as
// .aspx requires session, and session should be available there
// .jpg, or .css doesn't require session so session will be null
// as .jpg, or .css are also http request in any case
// even if you implemented URL Rewritter, or custom IHttp Module
if (Context.Handler is IRequiresSessionState
|| Context.Handler is IReadOnlySessionState)
{
// here is your actual code
// check if session is new one
// or any of your logic
if (Session.IsNewSession
|| Session.Count < 1)
{
// for instance your login page is default.aspx
// it should not be redirected if,
// if the request is for login page (i.e. default.aspx)
if (!Context.Request.Url.AbsoluteUri.ToLower().Contains("/default.aspx"))
{
// redirect to your login page
Context.Response.Redirect("~/default.aspx");
}
}
}
}
Edit 1: Explanation & Conclusion
As one of the guys told about ASP.NET Application Life Cycle.
There are plenty of events that occurs.
Actually events in Global.asax raises in the following sequence
Validate Request // looks just internal mechanism
Perform URL Maping // looks just internal mechanism
Raise the BeginRequest event.
Raise the AuthenticateRequest event.
Raise the PostAuthenticateRequest event.
Raise the AuthorizeRequest event.
Raise the PostAuthorizeRequest event.
Raise the ResolveRequestCache event.
Raise the PostResolveRequestCache event.
Just selects a class who implemented IHttpHandler for the application // looks just internal mechanism
Raise the PostMapRequestHandler event.
Raise the AcquireRequestState event. just before raising this event asp.net loads the State like Session
Raise the PostAcquireRequestState event.
Raise the PreRequestHandlerExecute event.
Call the ProcessRequest method
Conclusion: All the events before AcquireRequestState event don't have Session object, because Session is not loaded by ASP.Net, so any event from *"AcquireRequestState** event gives Session object therefore this problem solves.
However some checks are required as I mentioned in above code
One method would be to have a Page baseclass that performs this check on Page_Init. Another method would be to piggy-back off of #K Ivanov's idea with putting it in the Global.asax. While Session is not available during Application_BeginRequest it should be available in the method Application_AcquireRequestState. For not standard web requests, this should provide access to the session to perform what you want.
in the Application_BeginRequest of the Global.asax
so to summaries the ideas we have:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if ((Session.Count == 0) &&
!(Request.Url.AbsolutePath.EndsWith("default.aspx",
StringComparison.InvariantCultureIgnoreCase)))
{
Response.Redirect("~/default.aspx");
}
}
Be careful with your approach.
I don't think it is a good idea to validate globally if certain Session information exists or not. It can get become very messy, very fast. Only certain pages might require specific Session variables, which differ from other pages. Further down the road you might even have some content which can be safely accessed without any existing Session state. Then you will have to start coding exceptions to your rule...
What type of information are you storing in these Session variables? If you elaborate further we could maybe come up with a better approach.
Be careful with Session.Count == 0, because things like Session_ID are, implicitly, stored in the session.
Preferably look for something like (Session["UserName"] == null), where Session["UserName"] is where you, explicitly, store something of the user.
Other than that, Global.asax is the best place (ASP.NET Application Life Cycle).
ALSO, you have to enter a check that you are not currently on ~/default.aspx, because otherwise you will have an infinite loop.
I have my own SQL based session class. I want to automatically commit the data in the session at the end of program execution (i.e. at the end of serving the page request). Do object destructors (finalizers) not get executed at the end of every request? Is there anyway of doing this instead of having to explicitly call a Dispose() method every time I am done with my session object?
One possibility is by using the global.asax. There is a handler for the end of a request, in C# the call inside global.asax.cs would look something list this:
protected void Application_EndRequest(object sender, EventArgs e){
//perform action - you have access to the HttpContext
}
You have to watch out for what is going through the handler though - depending on your configuration your assets (stylesheet, images, etc.) may also be hitting this request so you may have to devise a way to ensure only your pages have the actions taken on them.
In C#, finalizers are non-deterministic, which means you don't have any guarantee when it will be executed. So, no, you can't use them for your scenario.
I see two ways to approach this:
Programmatically calling Dispose at some point towards the end of the page's life cycle (or via the global.asax as mentioned by Michael G.).
Have your SQL based session class wire itself up to a page event (such as the Unload event) to do whatever actions it wants to clean itself up.
UPDATE:
In response to your question about suggestion #2, I will expound a bit. This option would be to somehow allow your SQL based session class to gain a refernce to the web page instance. One option (which I'll show below) would be to use the constructor of the SQL based session class to obtain a reference to the web page. Then the SQL based session class can sign up for any event that it desires in order to know what is happening to the page.
namespace SomeNamespace
{
using System.Web.UI;
public class SqlBasedSession
{
public SqlBasedSession(Page webPage)
{
webPage.Unload += new EventHandler(webPage_Unload);
}
void webPage_Unload(object sender, EventArgs e)
{
// the web page is being unloaded so this class can
// cleanup it's resources now
}
}
}
Let me know if this still isn't clear.
I would suggest to go with IOC container provider for these kind of stuff. You can hook them up, to the end of a request and execute some code, especially good for some transactional stuff.
I have been using Autofac, it has OnActivated() method, which I use to hook my transaction commits to on activation of session.
On my login web page (i.e. the first page the user hits) I have code of this form:
public class MyPage : System.Web.UI.Page {
private MyClass _obj = new MyClass();
...
MyClass has the constructor:
public MyClass() {
var sess = HttpContext.Current.Session; // no problem here
sess["MyValue"] = 123; // throws null ref exception coz sess is null
}
As I've commented, the call to sess["MyValue"] throws a null reference exception, because the HttpContext hasn't yet created the session object.
So when is it safe to start accessing the Session object? I don't want to give up on the inline declaration/initialization of _obj; that's very convenient for me! What alternatives do I have?
You should be able to access the Session in or after the Page's OnInit event, or PreInit if you're that bothered. Before that, and you're dicing with death.
The session is created in aquireRequestState event of Http Module pipeline. I have tried to explain this whole thing below in detail.
We have below events in Http Module pipeline:
(Pre - Page Life Cycle)
1. BeginRequest
2. AuthenticateRequest
3. AuthorizeRequest
4. ResolveRequestCache
5. AcquireRequestState
6. PreRequestHandlerExecute
Post - Page life cycle
7. PostRequestHandlerExecute
8. ReleaseRequestState
9. UpdateRequestCache
10. EndRequest
Now, as we are aware, the first event in page life cycle is PreInit.
You are trying to create the object _obj before PreInit event. In the request life cycle, this process of creation of object and execution of constructor is done during ResolveRequestCache i.e; before AcquireRequestState event (since this is directly created in class and not any method). As expected, the session will still not be available in the constructor as AcquireRequestState is not yet executed.
PreInit method in page life cycle is called after AcquireRequestState and hence the session is available there.
Conclusion:
Earliest session operations can be done anytime after AcquireRequestState in Http Modules (if you are intercepting the request programmatically) or in/after PreInit method.
If the user is on the first page of the site, then the Session has no objects in it. You should definitely check the value before assigning to it.
if (Session["MyValue"] == null)
Session.Add("MyValue", "");
Session["MyValue"] = "123";
You can also add the Global.asax file to the project. That is where you can handle the Session_Start event.
You can look at the http pipeline. Rich Starhl has a nice article. . Your session objects are created/retrieved during aquireRequestState event. If you have HTTP Modules which intercept the request before this event, your session might not have been initialized