Global.asax problem - session_start fires twice

This is a second attempt to get a resolution to this problem with some new information.

I have a .NET application that has the following code in the Session_Start event:

Application("SessCount") += 1

Now when I display Application("SessCount") in an aspx page it sometimes (not always!) increments by 2 after starting the application. If I put a break point on 'Application("SessCount") += 1' it stops twice. The event is being fired twice.

I can't seem to resolve this problem. Can anyone suggest how I can track down this problem?

Who is Participating?

Ok i have been keeping my eyeon the site for most of the day and there have been no problems
I will be testing this this week but i feel you can use the code and test along side.

copy and paste this code into your global.aspx file, amending your existing routines, ie add any other code you may wish to run, be aware of any (exit sub)'s.
Any bugs let me know. I think there is one issue concerning a refresh post this session timeout but im not sure its still there. Like i said i will be testing this most of this week

keep me posted of any bugs you can find.

Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' Set our user count to 0 when we start the server
Application("ActiveUsers") = 0
End Sub
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
Try
'ok you must keep your main frameset source pages constant otherwise this
'wont work. In the same order of frameset declaration in your html or
'html framset page we start with a case if,
'each elseif is for each frame so if you have two frames you only need one elseif
'so frame 1's target = menu.aspx
'frame 2's target = sidebar.aspx
'frame 3's target = default.aspx
If LCase(Request.Url.ToString).IndexOf("menu.aspx") > 0 Then
'ensure this is a new session request (handles second load of website in another browser)
If Session.IsNewSession Then NewSession() : Exit Sub
'frame2 target = sidebar.aspx
ElseIf LCase(Request.Url.ToString).IndexOf("sidebar.aspx") > 0 Then
If Request.Cookies("SessionID").Value = Session.SessionID Then
If Session.IsNewSession Then NewSession() : Exit Sub
End If
'frame3 = test3.aspx
ElseIf LCase(Request.Url.ToString).IndexOf("default.aspx") > 0 Then
If Request.Cookies("SessionID").Value = Session.SessionID Then
If Session.IsNewSession Then NewSession() : Exit Sub
End If
End If
'Context.Response.Write("bugga boo " & Application("ActiveUsers"))
Session.Abandon()
Catch ex As Exception
Session.Abandon()
End Try
End Sub

Normally when user make a request to a page that contains a frameset it will first send the request to the web server and then the browser will send individual request from each page in frames. This means, if you have a page with frameset that contains 2 frames, the web server will actually receive three requests from the browser and each request carries the same session id. This occurs when the three pages have aspx extension. And if any of the page has extension other than aspx you'll get different behaviour.

Personally I don't really like working with frames and when I need to maintain session variables across pages in frames that would be my last option. If you can elaborate on what you are trying to achieve there're might be a workaround.

session variables are the same with or without frames. A session is dependant on the instance of your browser not your frame. I am dealing with a 3 frame htm page each frame uses aspx pages, my site is built on session vars with an SQL server back end.

The problem is despite each frame sharing the same session ID when the sesion is instantiated ie by declaring a variable the session_start event is still fired by each frame the first time the framset loads, so if you have a counter in the session_start rountine naturally you will get a false idea of the number of users. In turn if you decide to divide the counter by three you will be wrong again. This is because when the session timesout or is abandoned starting a new session while the browser window remains open, the session_start event is only fired once .... i have spent as long time debugging and testing this issue to no true resolution, the only reall answer i have found is "don't use frames" which is not an option for me

mm..that's strange.. I use an htm file as frameset and I get different session id for each frame, but ONLY on the very first request. Subsequent request they are all having the same session id. Any reason why this isn't happen to you?

what i mean is, each frame fires the session_start event the first time the frameset loads and they all share the same sessionID

[quote]
>if indeed frameset and its frames have the same session id for all requests then why session_start event is fired more than >once when the frameset loads at the first time?[/quote]

I dont know why it is fired more than once, perhaps something to do with the headers or the httprequest, its definately something low level, something to do with updating the session object in time before the next request is processed

I think this is an underlying issue yet to be curred with .NET, i dont know how to intercept the session
_start call, iv tried everything from checking session ID values to setting session vars all sorts of simple and complex solutions and none of them work. But i havnt given up yet

>> you may experience diff session ids if in your session_start you dont set a session var...
That's not quite true if you define Session_OnStart event in global.asax, asp.net will store session state even if there's no session variable defined in the application. It's clearly described in the article you posted above :o)

What about the Session_OnStart event? Is it fired for each request too? If the application defines a Session_OnStart handler, then the session state is always saved, even if empty. As a result, the session ID remains constant for all requests after the first.

Btw, when you come back here tommorow try to google with "Understanding session state modes + FAQ" and read the answer for question "I have a frameset page which has an HTM extension, and I found out each frame it contains display a different session id on the first request. Why?"

1] client loads homepage, homepage is an html framset of 3 pages, remember .html files dont run the session start event
2] from the single request has spawned 3 request for 3 .aspx pages or in your case 2
3] this is all under one request dont forget
4] ASP.NET retrieves request session id from http cookie (ASP.NET_SessionId) that is attached in http request of the client browser. ASP.NET then looks for the same session id in the configured state provider storage (Session dictionary, SQL Server or NT state service). If one does not exist ASP.NET generates a new session id and raises the Session_OnStart event.

heres the tricky bit, because the request hasnt finished processing nothing will be written in the state provider storage, it is only written once the request is complete, thats why on each frame load the session_start is fired

we need to somehow work around this issue or intercept and handle the triple (double in your case) call to session_start before it gets there.
Im actually considering a redirection .aspx page who's job is purely to obtain a single sessionid for the duration of the session and use this as the homepage, but thats messy and i dont really want to.

So, it's 'cos the page is part of a frameset. Yes, I can indeed verify that if I make the page displaying the counter the start page it all works correctly. As soon as as I make it the main page in the frameset the numbers go up by twos. Though, curiously, sometimes it does go up by one's!

At least I know the answer now. I am actually trying to count individual visits to the site of course. I can't dump the frames without a lot of re-work, so I'm stuck. I did think of the redirection option you mentioned in your last comment, Andre412, but as you say - messy.

I guess I'll just have to rely on the site stats.

Pity the MCSD course doesn't mention this problem in passing! How many hours of research do you think it would take to track this down from docmentation?

How about I split the points between the two of you - happy with that?

right basically every frame starts the session_start event we already know this, the trick is to only record one of the

so we are going to use the session.isnewsession property of the session object

it basically identifies if that particular request started the stream to the client and only one frame will have this property set to true

so in your global asaz file do this, and it should solve your problem,

Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
'initialise session only for one frame
If Session.IsNewSession Then
Application.Lock()
Application("ActiveUsers") = CInt(Application("ActiveUsers")) + 1
Application.UnLock()
End If
End Sub

I have yet to recieve a response. Rest assured i will find a solution to this because it affects my companies website. In fact i cannot rebuild the solution and make it live until this is solved because the code has now changed so much It would take ages to back track.

ravl, what's the counter exactly for? are you counting based on hits regardless of who, where or how many browsers have been opened in a same client machine? There're many factors to consider if you want to build a serious visitor tracker and relying on a single application variable definitely is not just enough.

Hi ihenry - I just want to count visitors to the site. I realise that this is a simplistic solution and not necessarily accurate, but I don't need that accuracy - just a ball park feel for visitor numbers. It's just that the frame problem produces such an obvious error I wanted to fix it. It seems to me that assuming a new session is a new visit is reasonable, short of reading the mind of the user.

Actually, what I'm doing is incrementing a counter in a database. The counter is displayed on the home page which is part of a frame set. I call a stored proc in the session_start to bump the counter. Using the application var was just a ploy to simplify debugging and eliminate the stored proc as the cause of the problem.

Andre412 seems determined to resolve a way to do this - so I'm waiting with baited breath!

Dr whatever his name is, isnt really as knowledgable as i had previously thought. He pretty much gave up before starting, if not he suggested rediculous solutions that would either not work or hinder the performance of the site. Im actually wondering how this guy got his doctorate

Ok i am testing a solution just now, however over the weekend the numbers started to drfit negative, i have made some minor adjustments this morning and wil monitor the count again over the next day or so. Fingers crossed.

first of all it checks for frame source page
Secondly it checks for a new session request
thirdly will start a new session providing the request pass's all logical questions

rules are
only start a new session if
a)the home page is being loaded for the first time
b)the session has timed out and they begin to navigate the site again
c)session_abandon is called

We use three objects to help us do this
1) the frames source page (constant)
2) isnewsession request (boolean and only true if its a new session request)
3) a cookie which we will be placing sessionID into on a sessino start, we only use the cookie to test for the other frames right to start a session.

session behaviour:
All frames gain a different sessionID every time a request is made, until such time as you instantiate a session variable from any frame, at this point all frames share the same sessionID, another thing to bare in mind is that even when the session times out, the sessionID remains in the header of the html page and is posted back to the server on the next request ie even when a session times out, on a refresh the same sessionID is used again for the new session, interesting i know thats where the cookie comes in.
So this means we can satisfy all rules using our objects, and its all done in session_start
if the rules are not adheard to we dont want to start a new session hence session_abandon, its odd this is placed in the sess_start but it seems to be working well.