How to allow a webbrowser to restart a session after it has expired?

R

Riaan

Hi guys!

I have an issue that needs urgent resolution. Imagine this scenario:

You have:
1 production server running Windows Server 2003, IIS6 and an instance
of MSDE 2000.
There is an asp.net app (written in C#) running which has the only
purpose of rendering a page with a "Next" button on it and some status
info. When the user clicks the next button, an event is written to the
database and the status info is updated and returned. The page thus
reloads showing the new status info.

There are twenty remote workstations, each with a touch-screen and
running a custom application (written in Delphi 7.0), which has an
imbedded web browser on the main form. The web browser connects to the
ASP application and renders the page.

The reason the web browser is imbedded in another app is simply because
the application interface exposes other functionality which has been
developed before. The web browser is just an add-in. The additional
advantage is that the Delphi application can load a client-side config
file which identifies the station:

Each workstation has a unique integer ID (1 - 20), which gets added
onto the URL for the TWebBrowser's Navigate() method, for example:

var url : string;
..
..
url := '\\server\asp_app?stationid=' + IntToStr(stationID);
WebBrowser1.Navigate(url);

The asp.net app reads the station id from the request to start the
session, this ID is linked to each database record as described above.

My problem is that I need a way to pass along the station ID every time
the user clicks the next button in the browser. I can use the Session[]
keys to store the station ID, but the moment the session expires, this
information is lost. The stationID only gets passed along in the
initial Delphi app TWebBrowser page request, subsequent clicks on the
next button have nothing to do with the delphi app, the web browser
works in isolation.

Increasing the session timeout is not a solution, as a day or more may
go by between next button clicks. I need a way for the session to
expire naturally, but when the user clicks the next button, the session
is reopened (or a new one created, passing back the station id) without
having to rely on the delphi app to monitor what is happening to the
session.

Fundamentally, what is required is for the web page itself to remember
the station ID, and pass it back to the web server. So the web server
must somehow add the station info to the page, and when the button is
clicked, the page is resubmitted, and the web server app somehow reads
the remembered info.

How do I do this? I assume that the button itself will have to be
runat="client", with some imbedded Jscript to re-initialise the
request?

And the remembered station id? Do I need a hidden field to store it?


Any advice would be very much appreciated! Thank you in advance!

Regards,
Riaan
 
R

Riaan

Hi guys!

I have an issue that needs urgent resolution. Imagine this scenario:


You have:
1 production server running Windows Server 2003, IIS6 and an instance
of MSDE 2000.
There is an asp.net app (written in C#) running which has the only
purpose of rendering a page with a "Next" button on it and some status
info. When the user clicks the next button, an event is written to the
database and the status info is updated and returned. The page thus
reloads showing the new status info.


There are twenty remote workstations, each with a touch-screen and
running a custom application (written in Delphi 7.0), which has an
imbedded web browser on the main form. The web browser connects to the
ASP application and renders the page.


The reason the web browser is imbedded in another app is simply because

the application interface exposes other functionality which has been
developed before. The web browser is just an add-in. The additional
advantage is that the Delphi application can load a client-side config
file which identifies the station:


Each workstation has a unique integer ID (1 - 20), which gets added
onto the URL for the TWebBrowser's Navigate() method, for example:


var url : string;
..
..
url := 'http://server/asp_app?stationid=' + IntToStr(stationID);
WebBrowser1.Navigate(url);


The asp.net app reads the station id from the request to start the
session, this ID is linked to each database record as described above.


My problem is that I need a way to pass along the station ID every time

the user clicks the next button in the browser. I can use the Session[]

keys to store the station ID, but the moment the session expires, this
information is lost. The stationID only gets passed along in the
initial Delphi app TWebBrowser page request, subsequent clicks on the
next button have nothing to do with the delphi app, the web browser
works in isolation.


Increasing the session timeout is not a solution, as a day or more may
go by between next button clicks. I need a way for the session to
expire naturally, but when the user clicks the next button, the session

is reopened (or a new one created, passing back the station id) without

having to rely on the delphi app to monitor what is happening to the
session.


Fundamentally, what is required is for the web page itself to remember
the station ID, and pass it back to the web server. So the web server
must somehow add the station info to the page, and when the button is
clicked, the page is resubmitted, and the web server app somehow reads
the remembered info.


How do I do this? I assume that the button itself will have to be
runat="client", with some imbedded Jscript to re-initialise the
request?


And the remembered station id? Do I need a hidden field to store it?


Any advice would be very much appreciated! Thank you in advance!


Regards,
Riaan
 
R

Riaan

Oh, and another thing, I must work in cookieless mode. so cookies
aren't a solution either.
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

How does the button currently send the form? Is it a submit button?

If the form is a server form (e.g. has runat="server"), the URL that the
form is posted to will be the same as the original URL, so it will have
the station id in the querystring.

Otherwise you can either put the id in the querystring of the URL in the
form, or put it in a hidden field in the form.

Hi guys!

I have an issue that needs urgent resolution. Imagine this scenario:

You have:
1 production server running Windows Server 2003, IIS6 and an instance
of MSDE 2000.
There is an asp.net app (written in C#) running which has the only
purpose of rendering a page with a "Next" button on it and some status
info. When the user clicks the next button, an event is written to the
database and the status info is updated and returned. The page thus
reloads showing the new status info.

There are twenty remote workstations, each with a touch-screen and
running a custom application (written in Delphi 7.0), which has an
imbedded web browser on the main form. The web browser connects to the
ASP application and renders the page.

The reason the web browser is imbedded in another app is simply because
the application interface exposes other functionality which has been
developed before. The web browser is just an add-in. The additional
advantage is that the Delphi application can load a client-side config
file which identifies the station:

Each workstation has a unique integer ID (1 - 20), which gets added
onto the URL for the TWebBrowser's Navigate() method, for example:

var url : string;
.
.
url := '\\server\asp_app?stationid=' + IntToStr(stationID);
WebBrowser1.Navigate(url);

The asp.net app reads the station id from the request to start the
session, this ID is linked to each database record as described above.

My problem is that I need a way to pass along the station ID every time
the user clicks the next button in the browser. I can use the Session[]
keys to store the station ID, but the moment the session expires, this
information is lost. The stationID only gets passed along in the
initial Delphi app TWebBrowser page request, subsequent clicks on the
next button have nothing to do with the delphi app, the web browser
works in isolation.

Increasing the session timeout is not a solution, as a day or more may
go by between next button clicks. I need a way for the session to
expire naturally, but when the user clicks the next button, the session
is reopened (or a new one created, passing back the station id) without
having to rely on the delphi app to monitor what is happening to the
session.

Fundamentally, what is required is for the web page itself to remember
the station ID, and pass it back to the web server. So the web server
must somehow add the station info to the page, and when the button is
clicked, the page is resubmitted, and the web server app somehow reads
the remembered info.

How do I do this? I assume that the button itself will have to be
runat="client", with some imbedded Jscript to re-initialise the
request?

And the remembered station id? Do I need a hidden field to store it?


Any advice would be very much appreciated! Thank you in advance!

Regards,
Riaan
 
R

Riaan

SOLVED!!!

Göran, you're a five-star guy! A genius!

I tested what you suggested by having my asp.net app write to a text
file every time a new session starts and ends. I had mistakenly
believed that my Response.Redirect("startpage.aspx") was throwing away
the original query string, but it doesn't. The viewstate of the web
form (yes, it's runat="server") not only maintains the session id, but
clicking the button resubmits using the original ?stationid=# added on.

I have no more worries! Yeehaaaaw! (for now :p)

Thank you so very much! I have much to learn, and with folks like you
around, that will happen much faster.

Knowing that the query string is preserved, the session timeout becomes
irrelevant.

Thanks again!

Riaan
 
R

Riaan

Hang on, I spoke too fast.

It works the first time the session expires. The second time it
expires, the query strings get discarded, and it stops working.
Whyyyyyyy?

:-/

My poor hairline!
 
R

Riaan

Okay, I've figured out what is going on.

On my button click event, I was calling Response.Redirect() to refer
back to this same page.

What I forgot was that the action itself causes a postback. The
Response.Redirect() removes the query strings, BUT, the remote object
lifetime of the cached page on the server was around 5 minutes. The
viewstate was being cached and used for the new request, but eventually
it expires gets discarded, and the new requests do not have a viewstate
to get info from. So it's a brand new, raw request.

If you allow the form to postback by itself, then the viewstate saved
in the page HTML *ALWAYS* gets used.

This is cool, but it doesn't solve the problem of maintaining the state
between different pages. I'll have to use hidden form fields.
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

Why are you bothering with the session expiration at all? Just send the
value along from page to page.

If you do a Response.Redirect you have to include the value in the
querystring, or it will be lost.
 
R

Riaan

"Why are you bothering with the session expiration at all?"

Well, session expiration means that I cannot rely on session state
(cookies or URI) to maintain values.
The expiration of the page viewstate cache means that I cannot rely on
that to maintain the query strings when using Response.Redirect. (I
would like to be able to jump to other pages if I need to, so I need a
solution that works regardless)

"Just send the value along from page to page."

How do I do this? Please pardon my ignorance, but I've only been
working with ASP.net for two days. :-o

Thanks,
Riaan
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

Riaan said:
"Why are you bothering with the session expiration at all?"

Well, session expiration means that I cannot rely on session state
(cookies or URI) to maintain values.
The expiration of the page viewstate cache

The viewstate is not a cache, it's simply values that are stored encoded
in a hidden field. If you don't do a postback there is no viewstate.
means that I cannot rely on
that to maintain the query strings when using Response.Redirect.

It's not the viewstate that maintains the querystring of the form. The
action property of the form is just set to the URL that was used to
request the page.
(I
would like to be able to jump to other pages if I need to, so I need a
solution that works regardless)

Then it depends on how you jump to that page. If you make a redirect,
put the value in querystring. If you post a form, put the value in a
hidden field.
"Just send the value along from page to page."

How do I do this?

Either as form data or in the querystring.
Please pardon my ignorance, but I've only been
working with ASP.net for two days. :-o

Ignorance is simply cured by learning (unless combined with stupidity). ;)

Noone knows everyting, so we are all ignorant in some fields. :)
 
R

Riaan

I've been banging away at it for a couple of hours, and I've come up
with the following solution (using the page's ViewState) that seems to
work very well. I have no idea whether it's a winning hack or a kluge.
You decide :-D

// In Global.asax.cs:
public class Global : System.Web.HttpApplication
{
public static string STATION_ID = "StationID";
 
R

Riaan

Damn, I'm goooood :p.

Derived a class from UI.Page, overrode the Onload event, now no need to
init the page each time, just need to make sure each web form class
derives from TMyPage.

public class TMyPage : System.Web.UI.Page
{
// override the OnLoad event so we don't have to init the
// page everytime outselves.
protected override void OnLoad(System.EventArgs e)
{
PreserveState();
base.OnLoad(e);
}

protected void PreserveState()
{
if (Session[Global.STATION_ID] == null) // session expired?
{
if (ViewState[Global.STATION_ID] == null) // do we have a saved
view state?
Response.Redirect("InvalidRequest.aspx", true);
else
Session.Add(Global.STATION_ID,
int.Parse(ViewState[Global.STATION_ID].ToString()));
}
else //nope, grab it
ViewState.Add(Global.STATION_ID,
int.Parse(Session[Global.STATION_ID].ToString()));
}
}
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

My opinion is that you are making this much more complicated than it is.

Explicitly send the value from page to page, so that you have control
over what's happening, instead of trying to hold on to the value using
intricate pieces of code that run behind the scenes.

What you are doing now is to put the value in differnt places where it
might be available later, then later try to get the value from one of
the places where it still might be.

It's a bit like putting a pair of glasses on top of most tables and
desks and shelfs instead of putting them in your pocket, then when you
need a pair, fumble around on the nearby furniture... ;)
 
R

Riaan

I honestly have no idea what you mean when you say "Explicitely send
the value from page to page". What exactly do you mean? Saying that
this is what I need to do does not tell me what I need to do, if that
makes sense.

So how DO I pass a value from one form to another? Obviously, there's
no session state, so the page has to remember what values I want to
keep. How do I do that? Using a hidden form field? Using the form's
Viewstate?

I'm using ASP.NET 1.1, and my understanding is that individual pages
have nothing to do with each other, they are unaware of each other and
what data is carried by them. The server app simply serves each request
in turn without giving a damn about page history. That is why state
management via Session vars or cookies or whatever are required, to
"bridge" the flow of data between forms. Because I cannot rely on those
features, I have to roll my own.

This is exactly what I'm doing with the form's viewstate. Each request
rebuilds the session state (if expired) from the data stored in the
viewstate, and session timeouts become irrelevant. Remember that the
viewstate is out of scope when the session starts, so I have to use the
Session variables to save values. The moment that the page viewstate
becomes available (OnLoad), I save the session vars to the viewstate.
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

Riaan said:
I honestly have no idea what you mean when you say "Explicitely send
the value from page to page". What exactly do you mean? Saying that
this is what I need to do does not tell me what I need to do, if that
makes sense.

What I mean is that you should send the value in each request in a way
so that you certainly know that you can pick it up in the next page.
So how DO I pass a value from one form to another? Obviously, there's
no session state, so the page has to remember what values I want to
keep. How do I do that? Using a hidden form field? Using the form's
Viewstate?

That depends on how you are requesting the page.

For a GET request (a link or a redirect) put the value in querystring.

For a POST request (posting a non-server form) put the value in a hidden
field or in the querystring.

For a postback put the value in viewstate, in a hidden field or in the
querystring.
I'm using ASP.NET 1.1, and my understanding is that individual pages
have nothing to do with each other, they are unaware of each other and
what data is carried by them. The server app simply serves each request
in turn without giving a damn about page history. That is why state
management via Session vars or cookies or whatever are required, to
"bridge" the flow of data between forms. Because I cannot rely on those
features, I have to roll my own.

This is exactly what I'm doing with the form's viewstate. Each request
rebuilds the session state (if expired) from the data stored in the
viewstate, and session timeouts become irrelevant. Remember that the
viewstate is out of scope when the session starts, so I have to use the
Session variables to save values. The moment that the page viewstate
becomes available (OnLoad), I save the session vars to the viewstate.

That method relies on either that the session has not expired or that
you are doing a postback. If you request a page any way that is not a
postback when the session has expired, it will fail.
 
R

Riaan

Hmm. Some stuff to think about.

All my forms are web forms, and I only ever redirect in click events of
buttons or imagebuttons, using Response.Redirect(). It always works. It
hasn't failed on me yet. I've even set my session time-outs to 1
minute, left forms open overnight, and this morning they were still
working perfectly.

I am specifically not relying on postback, and it still works after the
session has expired...?
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

Riaan said:
Hmm. Some stuff to think about.

All my forms are web forms, and I only ever redirect in click events of
buttons or imagebuttons, using Response.Redirect(). It always works. It
hasn't failed on me yet. I've even set my session time-outs to 1
minute, left forms open overnight, and this morning they were still
working perfectly.

Yes, if you keep it that way the viewstate will work, as you use
postback for every request except redirects, and when you do redirects
the session won't time out in the short time between the redirect being
sent to the browser and the browser requests the new page.
I am specifically not relying on postback, and it still works after the
session has expired...?

Yes, you are. The viewstate is only available if you do a postback.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top