Share Session between Page in Page to Page Request - asp.net

My application is simple, I have 2 pages:
RSSProducer.aspx: A page that generates RSS (XML) feeds
RssConsumer.aspx: A page that retrieves the RSS feeds and displays it to the user in a repeater control. To do this I am using the System.Xml.XmlTextReader to fill a DataSet with tables based on the RSS-XML retrieved from the RSSProducePage. A table within the DataSet is bound to the repeater control.
For example, this is what I have in my RssConsumer.aspx page:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Session("permittedToViewSomeDetail") = True
Dim url = "http://localhost/DevSite/RSSProducer.aspx"
Dim reader As New System.Xml.XmlTextReader(url)
Dim ds As New DataSet()
ds.ReadXml(reader)
myRssRepeater.DataSource = ds.Tables(2)
myRssRepeater.DataBind()
End Sub
My problem is that user-authorization details are stored in Session in the RssConsumer page that need to be accessed in the RSSProducer page (in this example it would be Session("permittedToViewSomeDetail") that I need to access in the RSSProducer page); however, the Session identifier is not common between the two. This means that I cannot access the authorization details in the RSSProducer page.
The reason for why is fairly clear to me:
User's browser makes a request to
the RssConsumer page
Server generates a Session ID (which is stored in a cookie) if
there is no existing Session
Identifer
The RSSConsumer requests the RSSProducer page...which generates a
new Session ID every time because no
session identifier is ever going to
be found.
I tried using cookieless session so that I could pass the SessionID via the URL to the RSSProducer page as an experiment but for some reason the XmlTextReader doesn't work well with this method (but the desired shared session does work).
I've hit a brick wall here.
Does anyone know how to share session between pages when one page makes a request to the other?
Thanks,
-Frinny

I ended up taking a different approach to solving this problem. I moved the code out of the RssProducer.aspx page into the RssConsumer.aspx page. I am now able to apply the correct authorization to the feature and it's actually more efficient this way because I don't need to produce/consume RSS-XML any more.
Thanks to everyone who took the time to help me with this.
-Frinny

Related

How to store User ID of Logged in User in ASP.net VB.net

I am trying to store the UserId or/and UserName of the user. This is used to record user ID against any changes they make to data, insert, updates and deletes etc.
I have created a module and in that module added a Public variable vUserID. Here Lei the problem.
User A logs in and his id vUserID = 'A'. Another user (User B), the other side of the world logs in User 'B' and that vUserID then = 'B'. So now anything User A does gets recorded as he is User 'B', or that is how I understand it, as a Public variable will be accessible from anyone who logs in.
I understand the problem, or I think I do, please correct me if not, but what I am struggling with is the solution. I have tried to use a Protected and Protected Friend but these do not seem to be accessible throughout the program(website) when a user is logged in.
For completeness I get the User details by the following code which seems to work fine:
Dim mu As System.Web.Security.MembershipUser = System.Web.Security.Membership.GetUser()
Module1.vUserID = mu.ProviderUserKey.ToString()
Well, the issue is that you have ONE web server.
And the web server (for the most part) will process ONE web page at a time.
So, when a user clicks a button on a web page, before they click on a button, the web page is sitting on their desktop computer. it is NOT on the web server.
(and more important, all the code variables (code behind) are GONE! They do not exist yet!).
So, think of a web server as ONE computer. And say 5 users are going to use YOUR computer to edit a word document.
The first user sits down, opens word document, types in some text, and then closes word!
The next user sits down, opens word document, types in some text, and then closes word!
Remember, you don't have a computer for each user, but have ONE computer - the web server, and it has to "some how" service all users.
So, all the web server can do, is "process" a web page, one that is sitting on each end users computer (running the browser).
So, you have this:
And you do NOT have this:
In other words, the web page is NOT sitting "loaded" on the web server. it is out of scope.
Think of when you call a sub, use some variables in that sub, when you return/exit from that sub, ALL VARIABLES are gone!! (out of scope).
You MUST think of web pages like that sub - when you exit, they are gone, don't exist anymore.
So, you don't have this:
the web page is NOT in memory on the server, it is NOT loaded.
Thus, you don't have this either:
So, with above in mind, lets create a super simple web page to show this:
We will have a simple string variable, called MyZooVar.
We will put a button and label on the web page to set this varible.
we will then put another button on the form to show the value of the variable.
So, this:
<asp:Button ID="cmdSetZoo" runat="server" Text="set varable to zoo" />
<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
<br />
<br />
<asp:Button ID="cmdGetZoo" runat="server" Text="get value of var zoo" />
<asp:Label ID="Label2" runat="server" Text="Label"></asp:Label>
and the code behind is this:
Public MyZooVar As String
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Protected Sub cmdSetZoo_Click(sender As Object, e As EventArgs) Handles cmdSetZoo.Click
' set value to variable MyZoovar
MyZooVar = "Hello how are you!"
Label1.Text = "Value of MyZooVar = " & MyZooVar
End Sub
Protected Sub cmdGetZoo_Click(sender As Object, e As EventArgs) Handles cmdGetZoo.Click
' get/show value of zoo var
Label2.Text = "Value of MyZoovar = " & MyZooVar
End Sub
Note VERY close in above, the MyZooVar - we defined it at the top of module, so all buttons and code can use that MyZooVar.
So, we will click the first button, this code:
' set value to variable MyZoovar
MyZooVar = "Hello how are you!"
Label1.Text = "Value of MyZooVar = " & MyZooVar
And then we have a 2nd button, and this code:
Protected Sub cmdGetZoo_Click(sender As Object, e As EventArgs) Handles cmdGetZoo.Click
' get/show value of zoo var
Label2.Text = "Value of MyZoovar = " & MyZooVar
End Sub
what will happen when we run?
We see this:
So, in above, this is what occured:
we START with this:
You click a button, YOUR web page (not the 20 other users) is sent to the web server.
the page travels up to server,
You now have this:
Now and THEN your code behind runs. When done, your code behind MUST finish, else the page stays stuck up on the server side. When done, the whole page page makes the trip down back to the browser. And THEN the page is re-displayed and THEN any js code can run.
So when done? Your page makes the trip back down to the browser like this:
Note on the server side? Your web code (and MORE important variables) and EVERYTHING is disposed.
We now have this again:
Note HOW THE WEB PAGE IS NOT on the web server!!!!
the web server is waiting now for ANY post-back of a web page from ANY user, not just you the one user!!!!
So, now that I clicked the button to set the variable MyZooVar?
What happens if I click on the 2nd button, this code:
Protected Sub cmdGetZoo_Click(sender As Object, e As EventArgs) Handles cmdGetZoo.Click
' get/show value of zoo var
Label2.Text = "Value of MyZoovar = " & MyZooVar
End Sub
Well, the whole process starts over again!!!
We will find that the variable MyZooVar is gone, out of scope, and does not have our value!!!
So, the "term" for the above is what we call "state-less".
In other words, your code behind can't assume, hope, pray that the varibles in the web page will persit.
Now you can hope/pray/try to put some variables in a global code module, but as you found out, they are shared amoung all users. But WORSE, the web server will often say, hey, I don't need that memory, I'm just sitting here waiting for someone to click a button and send me THEIR web page.
As a result, not only will you find those so called global variables in that public code module shared between all users, you find that they OFTEN will not even stay in memory all that long. So, your code "sort of works" to try and use some global variables, but you find they OFTEN go out of scope, and will not even stay in memory.
So, web based software is VERY different then desktop software.
One big difference is that for desktop software, each user, each workstation has their OWN copy of the code.
With a web server, you have ONE web server, ONE computer, and it sole job is to process incoming web pages (that occurs due to a page post-back).
the process of a simple button click, whole web page travel up to web server, page is processed, and then whole page is send back to user? We call this a round trip.
So, you really do not have global variables in a web based application. You can try to use some, but as noted, they will be the same for all users, but MUCH worse, is they tend to go out of scope, and can be disposed (go away) at any old time - you have no control over this, and thus you simple can't adopt global variables in a web based system - they are "off limits", and the above so called round tripping, and that you have ONE computer and ONE web site that somehow has to service many users - not just you!!
So, in your case?
Why do you need to store/save the user ID in some variable?
You "already" are able to get the user id with the code you shared:
You can use this:
dim UserID as integer
UserID = Membership.GetUser().ProviderUserKey
So, since you can get the "user" id any old time with above ProviderUserKey, then no need exists to try and "save" the user id into some global variable, but as you found out, you can't rely, or even design your software based around a concept of global variables.
However, you can if you wish place values into what we call "session".
Session is in effect global to the ONE user, and it DOES persist between those so called round trips.
so, you could do this:
Session("MyUserID") = Membership.GetUser().ProviderUserKey
And then in code, any time, use
Session("MyUserID") to get the user "id"
But, since you have ProviderUserKey, then even session() should not be required here.

Property in viewstate different on one page to another

This is really weird error i'm getting and i'll try and explain as best I can.
I have two pages - Page 1 (form) and Page 2 (completed page)
From page 1 I put a variable into a database and then do a server.transfer to page two like so...
Server.Transfer("Page2.aspx", True)
On page 2 I then grab the variable called paymentOnHold which is set on Page 1 and goes into the database...
Here is how I set paymentOnHold on Page 1
Public Property paymentOnHold() As String
Get
Dim _paymentOnHold As Object = ViewState("paymentOnHold")
If _paymentOnHold IsNot Nothing Then
Return CType(_paymentOnHold, String)
Else
Return Nothing
End If
End Get
Set(ByVal value As String)
If Not String.IsNullOrEmpty(value) Then
ViewState("paymentOnHold") = value
Else
ViewState("paymentOnHold") = Nothing
End If
End Set
End Property
...
paymentOnHold = Date.Now.ToString("yyyyMMddHHmmss")
Here's how I grab the value on Page 2...
Dim myValue As String
If TypeOf PreviousPage Is Page1 Then
myValue = DirectCast(PreviousPage, Page1).paymentOnHold
End If
In my development environment where the databases are local the value in the DB and the value on page 2 both match - as you would expect...
In live environment the DB value is 3 or 4 seconds different (before) the one on Page 2 - even though I do not reset it or anything?
This has been driving me crazy for the last few hours and cannot work it.
Does anyone have any ideas/suggestions as to what might be causing this?
Thanks in advance
This could be an issue of saving the view state in first Page (form-1)
In asp.net Page lifecycle
1. Initalization (controls raise their Init event)
2. Load ViewState (Only on post back)
3. Load PostbackData
4. Load
5. Raise PostbackEvent
6. Save View State
7. Render
Server.Transfer() stops rendering the current page and starts rendering another one.That's why Server.Transfer() cannot be used to redirect to pages served by another server.
If you are doing Server.transfer before Event--> 6. Save View State you are not saving viewstate on the form-1
Solution
Response.redirect and session cache, as it is intended to exist per user and across multiple pages in the application.
Using ViewState in this manner is a brittle solution, because ViewState is not intended to exist outside of the scope of the page it was initiated in, much less passed between pages, which I realize you are not quite doing, but you are getting dangerously close to doing it.
The better approach is to use Session cache, as it was intended to exist per user and span multiple page requests.
Try this:
To store in Session, do this:
Session("PaymentOnHold") = [Date].Now.ToString("yyyyMMddHHmmss")
To retrieve a value from Session, do this:
' First check to see if the value is in Session cache or not
If Session("PaymentOnHold") IsNot Nothing Then
' Everything in Session cache is stored as an object so you need to cast it to get it out
Dim datePaymentOnHold As DateTime = TryCast(Session("PaymentOnHold"), DateTime)
End If
Now the Session value will be available no matter how you navigate to pages (Server.Transfer or Response.Redirect).

ASP.NET ScriptManager History url hash lost after redirect

I have seen several posts online complaining that Firefox maintains the history url hash after redirecting.. That is the behavior I am hoping for - and it happens in Firefox (11.0), Chrome (18.0), and Opera (11.61), but not IE (9) or Safari (5.1.2).
On my page, I have ASP.NET 4.0 history points set up and working (has been working for a couple years). I also pass a few querystring params to the page. What I am trying to do now is check the value of a new querystring param, and if it does not match what I am expecting, redirect to the same page with an updated value. I am using this mechanism to track the session of individual tabs of a browser so that when they have the same page open in multiple tabs, the session values dont step on each other from tab to tab.
Anyway, I have everything working correctly including the back/forward using ASP.NET History points - and when I visit a bookmark and the querystring param does not match, I redirect and change the querystring param to track the session, and the history state that is in the url of the bookmark is then used to reload the page to the state I want. But that only works in Firefox, Chrome, and Opera. Not IE which is the big one for me (based solely on our user base), and not Safari.
I have identified that in addition to (or perhaps because of) the fact that the url history state is not present, ScriptManager.Navigate is not called after the redirect in IE or Safari.
Is there a setting/option that I can set on the ScriptManager or during the redirect to maintain the History state in the url? If the history state was in the url, I could call ScriptManager.Navigate directly if I needed to, but the values are not present in the url.
If it helps at all, here's a listing of where I do the check and redirect. The ReportRunID is then appended to the session variable keys that need to be unique to each tab. I keep a listing of previous ReportRunIDs to keep track and to clean them out (after a certain time period, or when more than [MAX] ids are encountered) so that I dont overload server memory with these session entries.
Private Sub Page_PreInit(sender As Object, e As System.EventArgs) Handles Me.PreInit
If IsPostBack = False Then
Dim rrid As String = Request.QueryString("RRID")
If ReportRunIDExists(rrid) = False Then
ReportRunID = Now.ToString("_HHmmssfff")
Dim url As String = Request.Url.PathAndQuery
If String.IsNullOrEmpty(rrid) Then
Response.Redirect(String.Format("{0}&RRID={1}", url, _reportRunID))
Else
Dim idx As Integer = url.IndexOf("&RRID=")
Response.Redirect(String.Format("{0}&RRID={1}{2}", url.Substring(0, idx), _reportRunID, url.Substring(idx + 6 + rrid.Length)))
End If
End If
End If
End Sub
Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
'save current RRID/Page/Time to session
UpdateSessionReportRunID(_reportRunID)
End Sub
...
If my bookmarked url looks like:
mysite.com/mypage.aspx?Rpt=123&RRID=_095224678#&&state1=abc&state2=def...
In FF/Chrome/Opera after the redirect, my url looks like:
mysite.com/mypage.aspx?Rpt=123&RRID=_102176253#&&state1=abc&state2=def...
But in IE/Safari after redirect, my url looks like:
mysite.com/mypage.aspx?Rpt=123&RRID=_102176253
Any ideas?
After much more searching, I have come to the realization that History State hash is not sent to the server. It is stored in the querystring so that it is included in bookmarks, but it is accessed by the client-side scriptmanager which causes a postback to load the state values. Since the Server never sees the hash value in the querystring, I have no way of finding those values when a user follows a bookmark to that page.
This problem was introduced as I was trying to start tracking the session state of different browser tabs individually. In my code above, if the RRID parameter is empty or invalid, I have to redirect to self with a new RRID value. When I do that redirect the History State hash was being lost for IE and Safari (but not for the other browsers).
My workaround:
The problem is that I needed to include the hash value in my redirect, but that is not available from the server, so I decided to inject some javascript to the page to perform the redirect from the client where the hash is available.
I already had a Client Redirect extension helper method that I have used in different scenarios, and I modified it to include the current hash value:
<System.Runtime.CompilerServices.Extension()>
Public Sub ClientRedirect(ByVal Response As HttpResponse, ByVal url As String, Optional ByVal target As Target = Nothing, Optional ByVal windowFeatures As String = Nothing, Optional includeCurrentHash As Boolean = False)
If IsNothing(target) Then
If windowFeatures = String.Empty Then
target = ResponseHelper.Target._self
Else
target = ResponseHelper.Target._blank
End If
End If
Dim page As Page = CType(HttpContext.Current.Handler, Page)
url = page.ResolveClientUrl(url)
Dim script As String
script = "window.open(""{0}"", ""{1}"", ""{2}"");"
script = String.Format(script, url & If(includeCurrentHash, "#"" + window.location.hash + """, String.Empty), target.ToString, windowFeatures)
If target = ResponseHelper.Target._self Then
'execute after page has loaded
page.ClientScript.RegisterStartupScript(GetType(Page), "Redirect_" & Now.ToString("HHmmssfff"), script, True)
Else
'execute as page is loading
page.ClientScript.RegisterClientScriptBlock(GetType(Page), "Redirect_" & Now.ToString("HHmmssfff"), script, True)
End If
End Sub
Then in my Page_PreInit where I do the redirects, I changed that to do the ClientRedirect including the current hash, and that has gotten the desired result:
Redirecting the browser while maintaining the History State hash on all browsers.
'redirect from the client so that we keep the History State URL hash
Response.ClientRedirect(String.Format("{0}&RRID={1}", Request.Url.PathAndQuery, _reportRunID), , , True)

Why is the Request.Form.AllKeys collection empty after a POST and Redirect?

I have an aspx page where I want to post values to a new page and then redirect to that new page. I don't get any errors and the redirection occurs but the AllKeys collection is always empty.
Here's an example of my code:
Try
With strPost
.Append("User=" & strUserName)
.Append("&Session=" + strValue)
End With
Dim objRequest As Net.HttpWebRequest = _
Net.WebRequest.Create("http://localhost:57918/testproject/test.aspx")
With objRequest
.Method = "POST"
.ContentType = "application/x-www-form-urlencoded"
.ContentLength = strPost.ToString().Length
End With
Dim objStream As IO.StreamWriter = _
New IO.StreamWriter(objRequest.GetRequestStream())
objStream.Write(strPost.ToString)
objStream.Close()
Catch ex As Exception
Debug.Print(ex.Message)
Exit Sub
End Try
Response.Redirect("http://localhost:57918/testproject/test.aspx")
I have seen a few articles similar to this problem but none of them have helped. What am I doing wrong?
Why don't you just have your main page post directly to this other page?
If the process is:
Page A rendered to client
Client posts back to Page A
Page A code behind generates a request to Page B
Page A code behind redirects user to Page B
Page B rendered to client
Then between steps 4 and 5 you will lose all the post params. That's just how it works.
However, you could do the following:
Page A rendered to client, with the form post action set to Page B
Clients enters information and clicks submit
Post values go to page B for handling.
Another path would be to have Page A perform a redirect and pass the values on the query string. For example, Response.Redirect("/PageB.aspx?param1=value&param2=value")
If I'm correct in understanding this, you are expecting the POST values to be available in /testproject/test.aspx after the redirect.
Unfortunately it won't work like that. When you perform the WebRequest it's a one-shot post. A new request is created your page executes and then the request ends and all data associated with that page will be discarded.
When you redirect at the end of the example given that is a completely new GET request to a new instance of test.aspx. Your previous request's POST data will never be available.
You can either:
Redirect to the page and pass the User and Session values in the querystring
Store User and Session in the Session collection then redirect
If strUserName and strValue originate from another postback your could use Server.Transfer to transfer control to test.aspx and keep the current request's Form and QueryString collections intact.
The code above will result in two requests being made to http://localhost:57918/testproject/test.aspx
The webserver itself POSTs the values to the url. When the page runs this time the AllKeys collection will contain the values you posted.
The client's web-browser will perform a GET request against the page. Nothing will be posted. This time the keys will be blank.
In order to pass the parameters to the other page you could encode the values in the redirect URL:
Dim url as String = "http://localhost:57918/testproject/test.aspx"
url = url + "?User=" + strUserName
url = url + "&Session=" + strValue
Response.Redirect(url)
The values would then be available using the request object (e.g. Request["User"]).
update
If you don't want to show the data to the user; then you've really only got two other options:
Move the processing that was being carried out by test.aspx to the page that was generating the original query.
Save the User and Session values the the session state.

ASP.NET create a page dynamically

I am dynamically generating HTML which is stored in a string variable.
I would like to open a new window with a new page created from this HTML.
This seems too simple, but I just cannot find the solution.
I am using ASP.NET 3.5 and VS2008.
Thanks,
Paul.
Best idea would be to create an http handler, register it in your web.config file to handle the various request paths that you need to have dynamic content for, and then detect the content to display based on HttpContext.Current.Request.Path.
This way you don't have to save any files, and you write from your string variable to the output stream
You can try this in your new page:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.ClearHeaders()
HttpContext.Current.Response.ClearContent()
HttpContext.Current.Response.ContentType = "text/html
HttpContext.Current.Response.Write(YourString)
HttpContext.Current.Response.Flush()
HttpContext.Current.Response.End()
End Sub
Create an .ashx page that takes a query string, e.g. pagebuilder.ashx?pageid=12345
The purpose of this page is simply to lookup in a session id based on the pageid query string. e.g.
var page = Session["PAGE_" + QueryString["pageid"]].ToString();
Response.Write(page);
On the page that generates the html in a variable, store the variable in Session at Page_Init
` ["PAGE_12345"] = generatedHtml;
Then on Page_Load, generate a javascript that opens to the url pagebuilder.ashx?pageid=12345.
That's it. You will be able to open your newly generated html in another window.

Resources