Avatar billede SilenceWar Nybegynder
06. december 2010 - 20:21 Der er 14 kommentarer og
1 løsning

Session update

Heey eksperter.

Jeg har et brugersystem pt. som ser således ud:


<%
strConn = "Driver={MySQL ODBC 3.51 Driver};server=***;Database=***;uid=***;pwd=***;"
set Net= Server.CreateObject("ADODB.Connection")
Net.Open strConn
strIP = Request.ServerVariables("REMOTE_ADDR")
%>
<%
function login()
if session("BrugerID") = "" then
response.redirect("http://warsofrome.dk/v1/")
end if
end function
%>
                                            <%
  strUID = Trim(Replace(Request.form("username"),"'",""))
  strPWD = Trim(Replace(Request.form("password"),"'",""))
  Dim proxyIP, normalIP, strDato
proxyIP    = Request.ServerVariables("HTTP_X_FORWARDED_FOR")
normalIP    = Request.ServerVariables("REMOTE_ADDR")

If proxyIP = doublequote Then
  'Hvis brugeren ikke er bag en proxy server
  strIp = normalIP
Else
  'hvis brugeren er bag en proxy
strIp = proxyIP
End If

if strUID = "" OR strPWD = "" then
response.redirect("http://warsofrome.dk/v1/")
end if
    Set rs = Net.Execute("SELECT * FROM brugere WHERE username = '" & strUID & "' AND password = '" & strPWD & "'")
    If Not (rs.BOF Or rs.EOF) Then
        intUID = rs("id")
        UserName = rs("username")
        Session("brugerid") = intUID
        Session("username") = UserName
    strSQL2 = "Update brugere set Online='Online' where id=" & intUID
    Net.Execute(strSQL2)
   
set VHenter = Net.Execute("SELECT * FROM  byinfo WHERE  ejerid='" & session("brugerid") & "' ORDER BY bynavn asc")
if not VHenter.eof or VHenter.bof then
    strRedirection = VHenter("id")
response.Redirect "Update.asp?Village="& strRedirection &""
    Else
response.redirect("http://warsofrome.dk/v1/")
end if
%>


<% end if %>
<%
response.redirect("http://warsofrome.dk/v1/")
%>



Som default skulle en session gerne sætte sig selv med en timeout=20 minutter..

Men.. Af en eller anden grund bliver min session afbrudt i tide og utide..
Er der nogen der har en måde, at holde denne session opdateret på? Jeg mener - så den ikke bliver afbrudt så længe brugeren er online??

Jeg håber I forstår hvad jeg mener. Ellers spørg.

Med Venlig Hilsen
SilenceWar
Avatar billede softspot Forsker
06. december 2010 - 22:14 #1
Det kan skyldes at din application pool brager ned og dermed foretager en recycle, som igen bevirker at alt hvad der hedder session- og application-data smides væk.

Prøv evt. at kigge i eventloggen på serveren for at se om der skulle være tegn på ustabilitet i IIS. Alternativt kan du lægge en lille rutine i global.asa, som skriver til en log-fil hver gang applikationen startes. Så skulle det være til at spore om der sker uventet recycling af din app-pool.

En anden (lidt mere eksotisk måske) mulighed, kunne være at du skifter mellem forskellige applikationer på dit site (hvis du har sat en mappe til en ny applikation på sitet) eller måske endda helt skifter domæne... så vil session naturligvis ikke bæres med over...
Avatar billede SilenceWar Nybegynder
07. december 2010 - 10:51 #2
Først og fremmest - hvad mener du med applikation?
Koden ovenfor er blot til, at registrere at brugere logger ind på sitet..?


Den sidste mulighed du nævnet, altså den eksotiske.. Betyder det, at en session kan mistes såfremt man bliver sendt fra:

../Game/index.asp

til

../Game/Building/palads.asp

???

Ellers tror jeg også at jeg er forvirret der.. Det med domænet er selvfølgelig rigtigt :) Det sker heldigvis heller ikke :)


Er der en nem løsningsmulighed man kan gøre for, at undgå denne session lukkes på steder den ikke burde?
Avatar billede softspot Forsker
07. december 2010 - 12:52 #3
En (web)application er et separat adresserum, hvor dit site kan køre uden at blive "forstyrret" af andre (web)applikationer, dvs. at bla. session- og application-objekterne kun omhandler det der findes i den pågældende application. Et typisk setup er at et domæne er en application, men man kan gøre undermapper til separate applications, som så har sit eget separate hukommelsesområde at "lege" i og dermed altså heller ikke deler session- og application-objekterne med application for selve domænet. Bemærk at flere domæner godt kan dele samme application, men sessions er typisk styret af cookies og de er bundet til et domæne, hvilket betyder at sessions ikke kan bruges på tværs af domæner (f.eks. vil domæne1.dk og domæne2.dk ikke kunne dele session-variable - jeg er lidt usikker på om det er muligt på tværs af subdomæner, som f.eks. sub1.domæne.dk og sub2.domæne.dk).

Mht. om session mistes hvis man skifter til en undermappe, som du illustrer med

../game/index.asp

og

../game/building/palads.asp

så er det altså kun hvis mappen building er en separat application... men det tvivler jeg nu på den er - det kræver en handling fra din side at gøre en mappe til en separat application, så det er nok ikke det der er problemet :-)

Jeg ville nok prøve at undersøge eventloggen på serveren, for at se om der skulle være tegn på om din IIS melder om jævnlige fejl eller det trick med global.asa jeg også nævner.

Du kan evt. kontrollere opsætningen på dit sites application-pool (den process i IIS som sørger for at håndtere funktionen af et eller flere sites), for at se om der skulle være noget påfaldende omkring opsætning af recycling af worker processen.

En mulighed i den forbindelse er i øvrigt at din applicationpool er sat til at benytte flere worker processes, hvilket giver problemer med session- og application-objekter. Du skal sætte din pool til at benytte én worker process.
Avatar billede SilenceWar Nybegynder
07. december 2010 - 14:03 #4
Jeg har søgt rundt på en masse af det du lige har nævnt..
Men der er desværre altid et men..

Jeg aner ikke hvordan jeg kan hverken tjekke de oplysninger du nævner (og i det tilfælde: hvad jeg skal kigge efter) eller hvordan jeg ændre de forskellige ting.

Jeg har søgt rundt efter denne applicationpool - men desværre uden held.

Er du sikker på, at der ikke er noget galt med min kode?
Og skal der ikke være noget i en evt. include-fil der sørger for, at denne session bliver holdt ved lige - og derfor ikke bare afsluttes?
Jeg ved det ikke - spørger kun :)

I tilfælde af, at der skal ændres noget - er det så fra min side, eller fx fra Surftowns?
Avatar billede softspot Forsker
07. december 2010 - 14:20 #5
Er det en microsoft-server (og dermed givetvis også IIS) dit site kører på?

Hvis det er en microsoft-server og det er hos Surftown dit site hostes, skal du prøve at høre Surftown vedr. antallet af workerprocesser på den app-pool dit site er tilmeldt. Så ved de hvad der kan gøres (det er muligt at de ikke VIL ændre dette, men det skader jo ikke at spørge). Hvis der benyttes flere workerprocesser pr. pool og de ikke vil ændre det, bliver du nød til at styre dine sessiondata på en anden måde (men lad os tage den teori, når du ved lidt mere om Sufttowns opsætning af dit sites app-pool :-)).

Det eneste der kræves for at en sesion bliver holdt i live er, at ejeren af den pågældende session spørger sitet om data (f.eks. en opdatering af en side, som benytter sessions) indenfor den angivne session-timeout (som standard typisk er på 20 minutter).
Avatar billede SilenceWar Nybegynder
07. december 2010 - 17:53 #6
Det er en microsoft windows server, ja - og det er lige præcis en IIS.

Jeg skriver til Surftown i løbet af de næste par minutter - og skriver så igen herinde så snart jeg har modtaget et svar, hvilket jeg forventer i løbet af i morgen eller senest torsdag.
Avatar billede SilenceWar Nybegynder
13. december 2010 - 23:25 #7
Goddag - håber du stadig har denne tråd under overvågning :)

Jeg har i dag kl. 15.15 fået et svar fra Surftown.....
Det er dog ikke så godt - eftersom svaret lyder således:

"
Ang. sessions, så er det desværre et velkendt problem, at sessions der holdes på serveren ikke kan vare de 20 min de standard sættes til. Den primære årsag er at ramforbruget der er dedikeret til en application pool, ikke kan sættes højt nok.

Når grænsen for ramforbruget rammes, recycles poolen og alle threads der kører i den.
Dette betyder også at sessions bliver nulstillet.

Af samme årsag har vi oprettet den session state server som du også har fundet artiklen omkring.
Desværre gælder dette kun for ASP.NET, det er dog muligt at du kan blande ASP.NET med ASP og få den ønskede løsning, jeg vil dog klart anbefale at du overvejer at konvertere dine sites til 100% ASP.NET i stedet.

Vi har ikke mulighed for at løse dette problem for ASP kunder, da det er en shared application pool.
"

Hvad vil du foreslå mig? Lære ASP.NET eller blande?

Ved ikke om du ved det - men vil det kræve ekstremt meget, at konvertere ASP koderne om til en tilsvarende ASP.NET? :)

Håber du stadig er her ;)

Pointene er dine - håber bare du lige gider besvare dette :)

Hilsen
SilenceWar
Avatar billede SilenceWar Nybegynder
13. december 2010 - 23:35 #8
Faktisk gad jeg godt at vide det her i stedet :P
- Er det ikke muligt blot at sætte koderne sammen?

På en måde så denne kode:


<configuration>
<system.web>
<sessionState stateConnectionString="tcpip=wsws1.surf-town.net:42424" timeout="20" mode="StateServer" cookieless="false" />
</system.web>
</configuration>

Kan komme til at virke på en .ASP side? Har lige tjekket ASP.NET - og da jeg næsten er færdig med alt på min side er interessen der ikke for, at skrive alt om til ASP.NET.. :s
Avatar billede softspot Forsker
14. december 2010 - 12:35 #9
Jo, jeg er her stadig :-)

Jeg synes ikke det er let at konvertere fra ASP til ASP.NET. Hvis det skal gøres ordentligt skal du, efter min mening, konverete alt koden, hvilket kan være en større opgave, alt efter hvormeget du har lavet i ASP. Derud over skal du til at lære et helt nyt programmeringssprog og nogle nye paradigmer omkring bla. webform-håndtering, som er anderledes (hvis man ikke tidligere har arbejdet eventstyret programmering). Selvom ASP.NET er ASP overlegent på de fleste (hvis ikke alle) punkter, så må man også overveje den ekstra arbejdsbyrde der ligger i at lære det - og den er som sagt ikke lille...

Jeg er 98% sikker (sagt på jysk) på, at du ikke kan kombinere ASP.NET's og ASP's indbyggede sessionhåndtering, da de håndterer komprimering og opbevaring af sessiondata på forskellige måder. Det har altid været en af de store hurdles på vejen for konverteringsprojekter af denne slags.

Dermed ikke sagt at du slet ikke kan kombinere de to, men det kræver at du styrer dine sessions udenom (eller parallelt med) de indbyggede, så det vil givetvis kræve at du skal igennem det meste af din kode for at bygge dette ind i systemet. Dette kan dog være en fin investering, da du så i fremtiden kan begynde konvertering af dit system til ASP.NET i små bidder, da det jo så vil fungere begge steder uanset om det kører i ASP eller ASP.NET.

Bort set fra alt det, så er min vurdring, ud fra det som Surftown svarer, at du er nød til at håndtere dine sessions i databasen, da du ikke kan stole på den i hukommelsen. Det betyder umiddelbart, at du skal generere din egen session-nøgle og sende den med frem og tilbage mellem klient og server, samt hente data fra databasen på grundlag af denne session-nøgle, hver gang det er nødvendigt (her starter så en seriøs overvejelse af, hvornår man ent faktisk har brug for sessiondata, da det jo selvsagt er noget meget resursekrævende end den indbyggede metode). Man kan evt. kombinere denne metode med den indbyggede session-styring, således den indbyggede session vedligeholdes, samtidig med at den i databasen vedligeholdes. Hvis den indbyggede er blevet nulstillet, må man tjekke databasen for at se om der skulle ligge noget her. Hvis der heller ikke er noget i databasen, må man antage at dette er en ny bruger og handle derefter.

Hvis du er interesseret i at arbejde videre med denne metode og har yderligere spørgsmål hertil, må du sige til, så vil jeg se hvor godt jeg kan svare. Det er dog ikke noget jeg har implementeret i praksis, men det burde fungere (det er ikke mig der har opfundet konceptet :-))...
Avatar billede SilenceWar Nybegynder
14. december 2010 - 13:20 #10
Beklager hvis der er trykfejl i den kommende tekst - eftersom den er skrevet på mobilen :)

Så det du mener er egentlig, at jeg kan benytte mig af den indbyggede sessionmetode og i databasen uploade det sessionId eller hvad det hedder.

Så kan jeg få tjekket om der er gået mere end 20 minutter siden den indbyggede evt. Er blevet afbrudt og i det tilfælde nulstille databasen? Hvis der ikke er - kan jeg jo egentlig blot opdatere den, med ny tid samt nyt sessionId?

Er vi enige så langt?
Når jeg tænker over det burde det egentlig kunne lade sig gøre.

Kan jeg blot skrive en PM til dig i tilfælde af jeg har spørgsmål?
Jeg giver dig pointene nu :)

Tak for hjælpen :)
Avatar billede softspot Forsker
14. december 2010 - 13:53 #11
Nej, det er ikke nok med den løsning du skitserer, hvis du vil holde styr på andet end udløb af login (typisk vil du nok mindst have behov for at huske hvem det er der er logget ind dvs. et brugerid, og det skal du også gemme i databasen, da det jo vil gå tabt i tilfælde af at applicationpool'en "recycles" utidigt.

Du er simpelthen nød til at gemme samtlige værdier, du vil lægge i session, i databasen og så benytte den indbyggede session som en "write through cache". Arbejdsgangen for styring af sådan en størrelse må være noget i stil med denne liste:

request fra bruger =>
1. check memory-session (mem-session).

2a. hvis mem-session eksisterer, så anvend den og opdater timestamp i database-session (db-session).

2b. hvis mem-session ikke eksisterer, så check om der er en db-session (på grundlag af den nøgle du selv har genereret).

2b1. hvis der findes en db-session, så indlæs session-data til mem-session.

2b2. sæt timestamp i databasen

3. send svar til klienten...

Det er naturligvis vigtigt at du også opdaterer evt. ændringer til session i databasen, samtidig med at du ændrer dem i mem-session.

Hvis det skal sikres lidt mere i forhold til webgardening (det at der kører flere workerprocesser (WP) i samme applicationpool), så bør du faktisk holde et timestamp for opdatering i hver mem-session og i db-session, da opdatering af session fra en WP ikke vil opdatere de andre mem-sessions i andre WP'er og de andre mem-sessions dermed vil komme ud af sync med db-session. Dette vil ikke være åbenbart, når et request rammer en anden WP's session, da den jo stadig eksisterer og dermed ikke umiddelbart behøver opdatering fra db-session (men det kan du så ikke være sikker på :-))...

Du kan evt. tage dette koncept og pakke ind i en VBScript-class, så du ikke skal gøre alle disse overvejelser alle steder. Ulempen ved at skulle kode denne slags selv er, at du skal inkludere en fil alle steder hvor du har behov for at benytte sessions, men på den anden side kan de gøres næsten ligeså smertefrit at bruge den mere robuste session, som hvis du benyttede den indbyggede session-mekanisme alene.

Du skriver bare tillæg til denne tråd, hvis der er flere spørgsmål til dette koncept, så vil jeg svare så godt jeg kan :-)
Avatar billede SilenceWar Nybegynder
14. december 2010 - 14:34 #12
"2b. hvis mem-session ikke eksisterer, så check om der er en db-session (på grundlag af den nøgle du selv har genereret)."

Lige nøjagtigt! Det var det jeg tænkte at: "det var da nemt nok"..
Men men men..

Jeg er stødt på et problem med lige nøjagtigt det.

Da jeg ville teste dette koncept valgte jeg netop, at lave en database til sessions med disse kolonner:

brugerid
tid
aktiv

Deri kan der så fx komme til, at stå:
brugerid = 1
tid = 2010-12-14 14:05:50
aktiv = 1

Og det ville jeg så tjekke ind med - eftersom jeg allerede har en includefil der berører alle session-siderne i mit system.

Men problemet er så netop det jeg forstår du også mener, at jeg skal kunne kende hvilken kolonne i databasen jeg skal hente ned senere?

Jeg havde tænkt mig blot, at hende den fra databasen hvori brugerid= session("brugerid") - indtil jeg kom i tanke om, at den jo skal hente det i databasen såfremt session("brugerid") er død..

Hm, har du en idé til hvordan jeg kan opstille databasen således, at jeg kan hente lige nøjagtig den kolonne der hører til den bestemte bruger?


Det er bare i orden - tak ;)
Avatar billede softspot Forsker
14. december 2010 - 15:12 #13
Ja, du skal lægge en nøgle i en cookie i stedet for i session. Det er denne nøgle du skal finde dine db-sessiondata på grundlag af. Du skal helst generere en nøgle, som er fuldstændig tilfældig og helst en lidt længere en af slagsen, f.eks. noget i stil med:

982KJHAF7Jh098=AfasH

Altså store og små bogstaver, samt tal og de specialtegn som tillades i en cookie. Dette gør det sværere for en der forsøger at session-hijack'e, at gætte dine session-nøgler. Den faktiske teknik bag generering af sikre nøgler skal du nok finde på nettet. Det er ikke noget jeg har fedtet med i praksis. En tilfældig genereret nøgle burde dog være mere sikker end en fortløbende værdi...

Mht. formatet af din database, vil jeg anbefale at du laver et generisk format som tillader at du lægger et vilkårligt antal session-værdier i session, i stedet for at binde dig op på et fast antal værdier. Alternativt skal du gemme dine session-data i et blob-felt, som evt. indeholder XML-data eller måske binære data (hvis du da ellers kan finde et eksempel på hvordan man gør dette - måske ADO har nogle objekter til at hjælpe med dette, f.eks. Stream-objektet). Jeg forestiller mig noget i stil med dette format (name/value):

cookie_id
name
value

Når de så skal indlæses kører du noget kode i stil med dette (dette er kun løsningsmodellen for en applicationpool som ikke kører i en webgarden):

dim cookie_id, sql, cmd, rs

if isempty(session("brugerid")) then
  cookie_id = Request.Cookies("XSES") & ""
  if cookie_id <> "" then
    sql = "SELECT name, value FROM session WHERE cookie_id = ?"
    set cmd = Servere.CreateObject("ADODB.Command")
    set cmd.ActiveConnection = conn
    cmd.CommandType = adCmdText
    cmd.CommandText = sql
    set rs = cmd.Execute(, array(cookie_id))
 
    do while not rs.eof
      session(rs("name")) = rs("value")
      rs.movenext
    loop
 
    rs.close
    set rs = nothing
  end if
end if

Der tages i dette eksempel ikke højde for timestamp, men denne oplysning ville jeg vedligeholde i en separat tabel.

Nøglen til din db-session genereres på det tidspunkt der rent faktisk skrives data til din session. Det vil jeg placere i en anden funktion end den ovenfor illustrerede, således der ikke genereres session og dermed databaseaktivitet før det er nødvendigt.

Du skal være opmærksom på at hvis du skal genindlæse session for ofte, kan det skyldes at dine sessiondata er for store og derfor kan blive nød til at revidere din brug af session (eller at der er andre sites i din applicationpool som måske burde gøre det :-))...

Eksemplet er kun hurtigt smækket sammen, så der gives ikke nogen garanti for at det fungerer ud af boksen, men princippet burde i det mindste være illustreret. Hvis ikke må jeg jo prøve at uddybe mere... :-)
Avatar billede SilenceWar Nybegynder
14. december 2010 - 15:32 #14
Indtil videre synes jeg, at dette giver mening.
Selve koden minder også om noget jeg havde i tankerne - så det passer mig ganske glimrende :)

Jeg vil prøve, at skaffe denne kode til at generere den tilfældige kode :)
Tak for hjælpen indtil videre.

Jeg skriver hvis der er mere mærkeligt der dukker op - eller når problemet er løst :)
Avatar billede SilenceWar Nybegynder
14. december 2010 - 19:50 #15
Hejsa!

Jeg er desværre ked af at sige det men...

Det virker rent faktisk! :) (indtil videre i hvert fald - har været på hele aftenen uden at ryge af :))


Mange tak for hjælpen Softspot!

****************************
Til andre - Koden jeg har brugt til, at danne den tilfældige kode ser således ud:

<%
function RandomString( )

    Randomize( )

    dim CharacterSetArray
    CharacterSetArray = Array( _
    Array( 2, "=?-*!#%" ), _
        Array( 5, "ABCDEFGHIJKLMNOPQRSTUVXYZ" ), _
      Array( 5, "abcdefghijklmnopqrstuvwxyz" ), _
      Array( 5, "0123456789" ) _
    )

    dim i
    dim j
    dim Count
    dim Chars
    dim Index
    dim Temp

    for i = 0 to UBound( CharacterSetArray )

      Count = CharacterSetArray( i )( 0 )
      Chars = CharacterSetArray( i )( 1 )

      for j = 1 to Count

        Index = Int( Rnd( ) * Len( Chars ) ) + 1
        Temp = Temp & Mid( Chars, Index, 1 )

      next

    next

    dim TempCopy

    do until Len( Temp ) = 0

      Index = Int( Rnd( ) * Len( Temp ) ) + 1
      TempCopy = TempCopy & Mid( Temp, Index, 1 )
      Temp = Mid( Temp, 1, Index - 1 ) & Mid( Temp, Index + 1 )

    loop

    RandomString = TempCopy

  end function
%>

Så kan man blot <%=RandomString%> - for at se outputtet! :)
Hyg jer!



Endnu engang tak!

Hilsen
SilenceWar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester