.NET Master Page Session state variable not saving - asp.net

I'm trying to store the session state in a master page to keep track of the previous URL. Here's what I'm doing
Public Property PreviousPage() As String
Get
Return Session("theprevpage")
End Get
Set(value As String)
Session("theprevpage") = value
End Set
End Property
Private Function HandleSiteNode(ByVal sender As Object, ByVal e As SiteMapResolveEventArgs) As SiteMapNode
Dim currNode As SiteMapNode = SiteMap.CurrentNode.Clone(True)
Dim tempNode As SiteMapNode = currNode
Dim strPrev As String = PreviousPage
' Append parent pages query string back onto the parent's node URL
If Not tempNode.ParentNode Is Nothing Then
If strPrev.Contains("?") Then
tempNode.ParentNode.Url = tempNode.ParentNode.Url + "?" + strPrev.Split("?")(1)
End If
End If
Return currNode
End Function
And in the master page load function
If Not IsPostBack Then
AddHandler SiteMap.SiteMapResolve, AddressOf HandleSiteNode
PreviousPage = Request.UrlReferrer.ToString()
End If
Now, here is where it gets strange.
The first page is a login page the master load doesn't get called on. After I log in it then going to the main.aspx page, and it successfully saves the "login.aspx" page in the session state.
Now, when I go to navigate the 2nd time after logging in, the session state is set successfully, but by the time it gets into the HandleSiteNode which is called after the session was set successfully, the session still says the url is "login.aspx" and not "main.aspx"
No where else in the code am I setting this session state, it just seems to revert back to its previous value on its own.
No matter how many links I click & how many times the session is set, the Session variable will never change to anything else besides "login.aspx"
Help!
edit: Another odd detail, when I move the AddHandler line from master page into a non-master page, the session state is saved properly. However, if I try to move the Addhandler code into the Master page MainContent.Load function, it still doesn't work

SiteMapResolve is a static event.
This means that it doesn't have access to the session object. You'll note this if you put a breakpoint in your HandleSiteNode code and inspect the Session.SessionId property.
The examples on MSDN about the event all target the global.asax file which means that handler is really geared towards a single use of the site. Note that the MSDN example I linked to is a little jacked in that it attaches a new event on every page load, which will eat memory. The event should only be attached to once.
Click here for more info on potential ways to get around the issues.

Apparently, my web project has at least 2 different session states.
I can access the session state that contains the value I want by using
e.Context.Session("theprevpage")
This seems like a bit of a hack but it's working for me.

Related

What type of variable could I use for this?

What I am trying to do is simple in principle, but the lifecycle of ASP.NET pages is throwing a bucket of cold water into my day.
Here is the problem
We have implemented URL Redirection and I've inherited code that reads like this in Global.ASAX, on Sub Application_BeginRequest:
dv.Table = CommonFunctions.ConvertXmlFileToDataSet("/XmlData/WebAppFolders.xml").Tables("Application")
dv.RowFilter = "'" + fullOrigionalPath + "' LIKE '%'+ folder + '%'"
If dv.Count > 0 Then 'match on key to redirect
If fullOrigionalPath.EndsWith(dv(0)("folder") + "/") Then
Context.RewritePath(dv(0)("basePage"), True)
Else 'missing page in directory --> redirect
HttpContext.Current.Items("Raise404") = "true"
Response.Redirect("/" + dv(0)("folder"))
End If
Return
End If
Basically we are reading a large XML file that contains the URL redirects. That's working fine. The problem happens in the line...
HttpContext.Current.Items("Raise404") = "true"
In the context of Application_BeginRequest, the session object is not yet available, so I could not use it to store a flag which I named Raise404. Instead I had to resort to using the Items collection.
The problem occurs when the redirect takes place. The new page lifecycle destroys the Items array and overwrites it with a new empty one.
By the time I try to use my flag Raise404, it no longer exists on my page PreRender event.
To complicate matters we use master pages, and so I was asked to place the code that we want to execute in the master page
Ideally, if the Items array wasn't being destroyed, this code would work:
Private Sub Page_PreRender(sender As Object, e As System.EventArgs) Handles Me.PreRender
If HttpContext.Current.Items("Raise404") IsNot Nothing AndAlso HttpContext.Current.Items("Raise404").Equals("true") Then
Response.StatusCode = 404
HttpContext.Current.Items("Raise404") = Nothing
End If
End Sub
I am not sure what kind of variable I could use to store my flag and allow it to survive the redirect.
Any ideas?
Update: The problem is that the HTTP Handler servicing my request is System.Web.DefaultHTTPHandler, which does not implement IRequiresSessionState, and so when my request is being handled inside Global ASAX there is no session created. So, it seems like the solution will be to write a custom HTTPHandler that implements IRequiresSessionState, and use that for all my .aspx files. Even then, a session state is not created in Global.ASAX until PreRequestHandlerExecute is raised. So, putting it all together I think I need to write a custom HTTP Handler that implements IRequiresSessionState, and delay the redirection of the page until PreRequestHandlerExecute is raised where I will be able to store my flag into the Session state, and only after that, redirect my page.
Not very elegant, and I wonder if there will be any performance implications.
Have you considered using the query string for that?
Response.Redirect("/" & dv(0)("folder") & "?Raise404=true")
Then, in your Master Page, simply check QueryString("Raise404") and act accordingly.
The only drawback I can see is that a malicious client could deliberately add Raise404=true to the query string, which is not possible with your current solution. However, I do not see how that could do any harm.
As I suspected, my problem was directly tied to the fact that IIS 8 will avoid using an HTTPHandler that implements IRequiresSessionState if for performance reasons it detects that a session object is not needed, and so because the redirect code was happening during the Application_BeginRequest event, IIS was handling up to that point my requests using System.Web.DefaultHTTPHandler.
So, upon further research, I found this which was tremendous help:
IRequiresSessionState - how do I use it?
And I also documented myself on this article:
http://forums.iis.net/t/1094546.aspx
What solved my problem was to write a dummy HTTPHandler class. I added a new class to my app_code folder:
Imports System.Web
Public Class HTTPRequestHandler : Implements IHttpHandler, IRequiresSessionState
Private OriginalHandler As IHttpHandler
Public Sub New(handler As IHttpHandler)
Me.OriginalHandler = handler
End Sub
Public Sub ProcessRequest(context As HttpContext) Implements IHttpHandler.ProcessRequest
Throw New InvalidOperationException("HTTPRequestHandler cannot process requests.")
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
Public ReadOnly Property Handler() As IHttpHandler
Get
If Me.OriginalHandler IsNot Nothing Then
Return Me.OriginalHandler
End If
Return HttpContext.Current.Handler
End Get
End Property
End Class
Now, during Application_BeginRequest, session is not available but HttpContext.Current.Items is available. So, as the second article suggests, during PostMapRequestHandler I put a condition:
If HttpContext.Current.Items("Raise404") IsNot Nothing Then
Context.Handler = New MyNameSpace.HTTPRequestHandler(Context.Handler)
End If
And finally, that created the session object that I could finally use during PreRequestHandlerExecute:
HttpContext.Current.Session("Raise404") = "true"
Response.Redirect(HttpContext.Current.Items("Redirect"))
I will definitely not argue that this is not elegant, but it works and I can raise my 404 error during Page_PreRender on my master page.
I hope this may help others.
Cheers.

IE Session.Abandon()

IE seems a bit buggy when it comes on Abondoning the session. This is the whole code thats get executed:
Protected Sub logout_OnClick(ByVal sender As Object, ByVal e As EventArgs)
Session.Abandon()
Response.Redirect("login.aspx")
End Sub
It redirects to login.aspx but when i change the url to default.aspx its get in without checking it. In all the other browsers it doesnt and get you redirected because of the following code:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
If (Session("Naam") Is Nothing) Then
Response.Redirect("login.aspx")
Else
Label1.Text = "Welkom " + Session("Naam").ToString()
End If
End Sub
Is there any reason that IE doesnt abandon the session?
note//
I am not using log-incontrol what so ever
Try disabling/removing the autopostback and then re-test your page. I would guess that the autopostback is somehow keeping your session data active,maybe its being used in the postback? therefore all instance's dont get abandoned?.
Edit
When the Abandon method is called, the current Session object is queued for deletion but is not actually deleted until all of the script commands on the current page have been processed. This means that you can access variables stored in the Session object on the same page as the call to the Abandon method but not in any subsequent Web pages.
For example, in the following script, the third line prints the value Mary. This is because the Session object is not destroyed until the server has finished processing the script.
<%
Session.Abandon
Session("MyName") = "Mary"
Reponse.Write(Session("MyName"))
%>
If you access the variable MyName on a subsequent Web page, it is empty. This is because MyName was destroyed with the previous Session object when the page containing the previous example finished processing.
The server creates a new Session object when you open a subsequent Web page, after abandoning a session. You can store variables and objects in this new Session object.
The above is from the MSDN website.
Which all means that somewhere your session object is being used AFTER you have abandoned it.
I normally use the same code block as you do to log a member out of a session.
Session.Abandon()
Response.Redirect("default.aspx")
with the same code in the global.asax or global.aspx file too.

Clearing a session in ASP.NET

I'm a new developer, and I've been assigned the task of figuring out why our log out function is not working. I've tried every possible method I can find. Below is the log I've kept that includes the methods I've used.
Added a log out button to the CommonHeader.ascx form
Have tried numerous methods in the logout.aspx.vb form to get it to end or clear the session but none of them work.
a. ClearSession sub routine defined in the logout.aspx.vb form:
Session("Variable") = ""
FormsAuthentication.SignOut()
Session.RemoveAll()
Session.Abandon()
Session.Clear()
b. Also added this to the top of the Page_Load sub routine:
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache)
HttpContext.Current.Response.Cache.SetNoServerCaching()
HttpContext.Current.Response.Cache.SetNoStore()
c. Also changed the ClearSession sub routine to Session.Contents.Remove("Variable") from Session("Variable") = ""
None of these methods work. We use Siteminder, and I've been wondering if this is the root of the problem. I just can't find anything on clearing a Session that uses Siteminder. Also keep in mind this application is coded with Visual Studio 2003.
This is the code for the button I'm using in the ascx file:
athp:TopNavText Title="Log Out" NavigateUrl="logout.aspx" Target="_top"/
Then on the "logout.aspx" form I've tried just using one of the methods described above or a combination of each one. This is the code before I ever touch it:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ClearSession()
Response.Redirect("login.aspx")
End Sub
Public Sub ClearSession()
Session("Variable") = ""
End Sub
Finally figured out the solution, I originally did not define the domain upon deletion of the cookie which contained the siteminder session id. The code I used is as following:
Dim cookie3 As HttpCookie = New HttpCookie("SMSESSION", "NO")
cookie3.Expires = DateTime.Now.AddYears(-1)
cookie3.Domain = ".domain.com"
Response.Cookies.Add(cookie3)
Response.Redirect("login.aspx")
This question: formsauthentication-signout-does-not-log-the-user-out describes a problem with not clearing cookies even after calling FormsAuthentication.SignOut(). This sounds like your issue, they say it's a bug with .NET and as your using 1.1 this sounds distinctly possible.
HI friend please add the click event of the button in user control. And in the click event please add the following code and remove all the other code.
Session("Variable") = "";
look at this post
C# Clear Session
Whether its c sharp or vb the same rules still apply. You are calling session abandon then clear, but by the time you call clear the session should be gone anyway.
Clear keeps the session state along with the objects in it, so by calling it after abandon you could in fact be reinitializing a session for the user, but with cleared variables.
See this post for the order and proper way to kill the session and redirect to the login page if you have one
FormsAuthentication.SignOut() does not log the user out
The first thing to note is that, if you're using Forms Authentication, Session has absolutely nothing to do with whether or not a user is logged in.
Calling FormsAuthentication.SignOut will remove the forms-authentication ticket information from the cookie or the URL if CookiesSupported is false.
But it will have no effect on what is stored in Session.
UPDATE
Why do you think log out (FormsAuthentication.SignOut) is not working? What are you expecting to happen when you click on Sign Out, and what exactly is actually happening?
I'd get rid of all the code to clear Session and look at this. For example, look at the http traffic with a tool such as Fiddler: you should be able to see that the FormsAUthentication cookie is removed when you click on Log Out.

Can't get Session variable the way I want to

Partial Class Preferences_MyPreferences
Inherits System.Web.UI.Page
Dim userID As String = Session("UserID")
This is just a page in asp.net. I want to be able to grab the Session("UserID") but every time I try, I get this error:
Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the \\ section in the application configuration.
If I put that Dim userID inside say the Page_Load Event, then it works fine. Why does it have to be inside an event? I want to dim it once, and use it throughout the page.
Consider wrapping your call to the Session in a property in your code behind?
Public ReadOnly Property UserID() As String
Get
Return Session("UserID")
End Get
End Property
If you declare it as you have there, the variable is initialized and the session variable is expected to be ready for usage, but it is too early in the page life cycle to allow that. The preferred method would be as #p.campbell has suggested and wrap it in a Property or similar method. To answer the question though, the exception is generated because you are attempting to use session before it is available.
You need to read up on ASP.NET Page Lifecycles. The Session object doesn't become available until a certain point in the page lifecycle; if you want to grab the UserID once, you need to do it after the session becomes available.
The reason it doesn't work in your example is that the constructor for your Preferences_MyPreferences page is executed before the request object is available to the page. You should instead load it during the Page_Init or Page_Load event.

Dealing with Databinding Errors in ASP.net

This has been bugging me for a while but when I databind a control using with a Session variable as the parameter which has not been initialized there is an exception thrown which I can't seem to catch anywhere.
Ideally if the session varaible is not set I would just like to redirect but I can't seem to figure out where I need to check for this instance.
You must check the session object on page_init event.
Check it in your page load.
Sub Page_Load()
if Not Page.ispostback()
if session("Value") <>"" then
me.hiddenfield.value = Session("ValueName")
Else
Response.redirect("PAge.aspx")
End if
End if
End Sub
I tend to add some hidden fields as sessions eventually time out
then make the datasource use the hidden control for its reference

Resources