10. november 2011 - 16:24Der er
34 kommentarer og 1 løsning
Hvem er online - C# - session
Hej,
Når der logges ind startes der en Session["user"] hvor jeg lægger det pågældende bruger-id ned fra mysql-db.
Jeg skriver brugere ud i en løkke og så kunne man sige [i]if(Session["user"] == item["fldid"])[i]
Men det viser jo naturligvis kun ens egen onlinestatus.
Jeg er nød til at bruge en extern kilde som global.asax eller en cookie (jeg bruger en cookie men der smidder jeg kun pass og burgernavn ned)
Er der en der har et bud på hvordan jeg kunne gøre det med global.asax eller andre løsninger uden at skulle lave mit login system helt om? Og det skal jo først gælde efter login - session_start går jo igang så snart man er på login siden.
Du smider da forhåbelig ikke password ned i en cookie som du sender ud til brugeren igen ... ? ( Seriøst, tænk på sikkerhed, specielt med at det man høre nu )
Lad brugere ved hvert request updatere deres egen state ... last active etc.
Derudover kan du ... ved hvert request eller via en timer fjerne brugere igen.
Application.Lock() var list = Application["Users"] as List<UserInfo>(); // Findes bruger i listen, hvis ikke tilføj ham // Update last active time og måsek andre ting. Application.Unlock()
Eventuelt kan du bruge nogen af de lister fra: System.Collections.Concurrent
Det er et hashcrypteret passw. jeg lægger ned. (men jeg skal dog have renset texten så det ikke er muligt at lave SQL injection)
Jeg har forinden testet det som du skriver der
Application.Lock(); Application["online"] = 4;//manuelt id Application.UnLock();
HVordan vil du definere den liste? (jeg kan sagten lave den manuelt) - men det er i session["user"] informationen ligger og det lader ikke til at jeg kan få fat i den i Session_start i global asax.
Men du mener måske UDEN for global.asax?
Lad os sige jeg har en online id-liste i Application["online"] (som jo er nød til at blive skevet ud i en løkke)- hvordan vil du mixe den med selve brugerlisten jeg skriver ud fra db?
Hvordan laver du din sql i dag siden du har problemet tror du har problemet med sql injecttions ?
Du har ikke testet som jeg har prøvet at beskrive i hvert fald. :-) Problemet med en int i Application er lidt ... hvordan ved du hvornår brugere ikke er aktiv længere ?
public class UserInfo { public string Username{get; set;} public DateTime LastActive {get; set;} }
og så have en generic liste af overstående:
List<UserInfo> list = new List<UserInfo>();
Her skal brugere så selv holde øje med at opdatere sit eget UserInfo object i den liste.
Hvis LastActive er ældre end 10 mins, så fjern den bruger fra listen.
Det kan laves i global.asax i ReguestBegin eller en af de andre events der kommer.
Jeg skriver Mysql metoden i en class - så jeg tvivler på om det ville være muligt at manipulere med. Om en bruger er aktiv defineres blot ved sessions, cookie udløb eller logud.
Jeg tænker på at det jo slet ikke er nødvendigt med global.asax da Application er global(det er faret hen over mig i min udd. som webintegrator - har ikke haft brug for det før nu).
Jeg skal jo bruge en int id til at sammenligne med i den stationære brugerliste - du misforstår mig nok der - selve brugerlisten må ikke pilles ved, der skal kun stå om bruger er online eller ikke.
Når der logges ind sker dette efter godkendelse af pass: //det kan jo så erstattes/udvides med Application. Session["bruger"] = dt.Rows[0]["fldid"].ToString();
På en anden side skriver jeg så brugere ud: foreach (DataRow item in dt.Rows) { //brugere }
Jeg prøver lige selv at teste det med en class som du skriver(har kun arb med arrays).
1. hvordan vil du sammenligne den liste(efter den er smidt ned i en Application["online"]) ned i løkken som udskriver brugere?
2. jeg kan godt udskrive en List(hvis jeg nu vælger at udskrive den også) - men at gøre det fra en Application["online"] er også et af mine spørgsmål.
//Som jeg har testet sådan: Application.Lock(); HttpContext.Current.Application.Add("user", userid); Application.UnLock(); //udskriv litbrugeronline.Text = HttpContext.Current.Application["user"].ToString(); //men den vil åbenbart ikke ud i en løkke om jeg laver en variabel til den. (håber ikke jeg sprøger om for meget på en gang her :))
Åh ja..Jeg havde ikke set din sidste post. Jeg kom frem til en en pinlig løsning som bare tilføjer listen til den sidste indloggede.. xD .. hvilket naturlivis giver probs med adskillelse af obj i listen. Hvorfor lige en class til dette? - det er jo kun datatypen.
Men nu laver jeg det med en class.
Jeg starter med at tilføje brugernavn i forbindelse med UserInfo class.
Gu læser jeg da hvad du skriver og din hjælp er påskønnet..men lad mig lige forstå det. Nu har jeg ikke arb. med List og application før ... ellers spurgte jeg jo nok ikke herinde. Jeg ville jo nok sammenligne en value i session og application for at se hvem der er online - jeg ved ikke helt endnu hvordan application opfører sig - på hvilke måde den timeouter - i så fald bør kun den unikke bruger fjernes fra listen ved logout.
Uanset hvad så lad mig lige FØRST få listen til at fungere. //class public class UserInfo { //jeg tilføjer sidste aktivitet når det fungere public string _brugernavn {get; set;} } //i login event List<UserInfo> list = new List<UserInfo>(); list.Add(new UserInfo());//***
Application["users"] = list;
//ny måde for mig - om den er nødvenig her ved jeg ikke endnu - jeg får en fejl ved kun denne list = Application["users"] as List<UserInfo>;
if (list == null) { Application["users"] = list; }
foreach (UserInfo item in bst) { litbrugeronline.Text += item.ToString(); } ***først tog jeg udgangspunkt i http://www.c-sharpcorner.com/UploadFile/camurphy/csharpLists03302006170209PM/csharpLists.aspx Så jeg lavede class om som derinde - det fungerede heller ikke - der står kun "UserInfo" i udskrift. Nu er det rettet tilbage til en property som ovenstående. Jeg har lavet et obj af UserInfo og der kan jeg få fat i _brugernavn men hvordan jeg skal skrive det i list.add() ved jeg ikke med mindre jeg skriver class som på c-sharpcorner.
Jeg er ikke helt sikker på hvad du spørger om, men der er flere ting som er mærkelige.
//i login event List<UserInfo> list = new List<UserInfo>(); list.Add(new UserInfo());//*** Application["users"] = list;
Her overskriver du din liste i Application data ved hvert login, det er nok ikke meningen, da den altid kun vil indeholde 1 bruger så.
// Se om den allerede er en liste var list = Application["users"] as List<UserInfo>;
if(list == null){ // Hvis den er null er der ikke en liste. list = new List<UserInfo>();// Init en ny liste Application["users"] = list; // Sæt den i application data. }
// Nu har du den samme liste ved hvert login og nu kan du tilføje hvem der logger ind. // Ingen ide om hvor du får Username fra, så jeg har bare hardcoded det. Du bør nok også kontrollere om han allerede findes i listen. list.Add(new UserInfo{}{Username = "backsideofthemoon"});
foreach (UserInfo item in bst) { litbrugeronline.Text += item.ToString(); }
Hvis du har en lang liste ... 1000+ ... så er det langsomt da, da string concatanation er langsomt.
item er en class, derfor du ser UserInfo bliver printet, da det netop er hvad ToString() per default i en klasse udskriver. Du skal have fat i din property Username ( Ved ikke hvorfor du har lavet den om til at hedde _Username. Det er normalt navgivnignen for readonly fields.
Dvs overstående bliver til:
StringBuilder sb = new StringBuilder(); foreach (UserInfo item in bst) { sb.Append(item.Username + "<br />") }
litbrugeronline.Text += sb.ToString();
Hvad er "bst" forkorelse for? variable name bør så vist muligt være beskrivende for hvad listen indeholder uden at kunder andres forkortelse.
Mit problem var at udskrive List fra class samt at tilføje en bruger i class uden brug af en function - som her http://www.c-sharpcorner.com/UploadFile/camurphy/csharpLists03302006170209PM/csharpLists.aspx Jeg kan se du gør det med tuborgklammer der. Jeg havde ikke sat statements på i login fordi det blot var en test(havde jo netop det problem med overskivelse da jeg skrev det uden class - så jeg er godt klar over det). Jeg har lært at skrive propertys med underscore - jeg ved ikke helt præcist hvad readonly fields betyder. Ja bst variabel var en fejl fordi jeg stadig er i testmode. Jeg vender lige tilbage når jeg har sat det op som du skriver - tak for hjælpen so far.
Hvem har lært dig at lave properties i .NET med underscore?
private readonly string _String; // Read only field private string _String; // backing field til property public string MyString {get; set; } // Auto property
public string MySecondString { // Set, Get til backing field get{return _String; } set{_String = value; } }
Hvad gør jeg med tuborgklammer?
Du skal bare huske det er test kode for dig selv, så når du poster det, skal vi læse det :-) ... jeg gør det selv, men ofte kræver det ikke mange ms mere at have et mere sigende variable navn.
Den artikel skal du ikke kigge på, selvom det måske er test kode han laver, så er den fyldt med "design fejl", mend et er en helt anden sag.
Tror ikke der var nogen spørgsmål jeg mangler at svare på ellers må du sige til.
1.Jeg har vændet mig til properties med underscore fordi det stod undervisningsmat. og så ved man man har fat i dem fra code behind...what can i say...: D 2.Du hiver fat i propertie i list.Add(new UserInfo{}{Username = "backsideofthemoon"}); ... det virkede nu ikke men istedet som list.Add(new UserInfo{Username = "bruger"});(med kun en' klamme - hvilket jo er logisk nok, men nu har jeg lavet class om til nedenstående). 3. "Du skal bare huske det er test kode for dig selv, så når du poster det, skal vi læse det">> det tænker jeg nu også meget på og der var også visse ting jeg rettede til men troede at "bst" gav sig selv blot som en variabel der skulle skrives - men det var en fejl..: D --------- Det lykkes mig faktisk at få det hele til at fungere med remove og contain og jeg forstår det - til dette har jeg naturlivis måtte skrive class som nedenstående hvilket du sikkert også giver mig ret i:
public class UserInfo : IEquatable<UserInfo>
{ public string _brugernavn {get;set;} public int _id { get; set; }
public bool Equals(UserInfo other) { if (this._id == other._id && this._brugernavn == other._brugernavn) { return true;
} else { return false;
} } } ------ Så skal jeg også have smidt en lastactive ind så jeg kan bruge en timer på den - eller kan du forestille en anden måde når bruger lukker ned for browser uden at logge ud og dette info ville jeg jo egentligt gerne have smidt i database også? Har forsøgt at få kode til at køre i session_end i global.asa....men uden held.
Men skriv lige et svar så jeg kan få smidt points ud - tak for hjælpen.
1) Jeg ville stoppe med det, da du vil få tæsk alle steder for at gøre det. Netop da readonly field har samme navngivning.
2) Jeg skriver fra min fantasi, så typos kan forekomme. Godt du ikke er en af dem som så bare siger "virker ikke", men selv kan rette de fejl :-)
3) Jeg siger det mere for at gøre folk opmærksom på det. Selvfølgelig kunne jeg godt i dette eksemple.
4) Hvis du læser på MSDN og andre sider skriver de at man ikke altid kan være sikker på at Session_End bliver kørt ... derfor skal du have en global oprydnings mekanisne i din Global_Asax der kigger på LastActive og ser om brugere eventuelt skal fjernes. Dette kan også laves med en Timer i Global_Asax.
Alt efter antal brugere etc.
Nemmere er at lave en clean up på hver Request_Begin, for at se at det virker. Husk ved hvert request skal brugeren selv sætte sin nye LastActive variable på hans UserInfo object i Application["users"] listen.
Jeg tænkte mere på at lave et tjek på hvis der findes et id i List som som er timet out i den sideløbende Session... så skal den pågældende bruger fjernes fra listen. Jeg grubler lidt over hvordan jeg skriver det..: D
Jeg forstår ik helt på hvilken måde jeg skal bruge det sidste tidspunkt brugeren har requested noget - hvad det skal sammenlignes med ..så brugeren kan slettes fra listen - jeg foretrækker at bruge den metode jo..
Problemet med timeout er at du ikke altid kan være sikker på at få det.
Hvis du ved en bruger klokken 20:12 har lavet et request ... og klokken nu er 20:37 ... så har han jo ikke lavet noget i 25 mins. Så vil jeg i hvert fald mene man ikke er aktiv længere.
Ja det er jo enkelt nok (men det kunne jo være brugeren var faldt i staver..kidding:)) - men så skal man jo justere det i forhold til hvad man har sat cookie til(i mit tilfælde en time) istedet for bare at lade session styre det hele.
Og det er jo ikke session timeout jeg skal ha fat i.. jeg skal bare tjekke om id'et fra List er i den.
Men jeg vil da lige prøve det med tid uden cookie.
//Men i mit if statement er der en rød streg under lastactive // - den ber om en propertie .. og det burde den jo have i sig class..som den er skrevet ovenover.
if (liste.Contains(new UserInfo(Convert.ToInt32(item["fldid"]), item["fldbrugernavn"].ToString(), lastacive))) { online = " Online";}
//jeg kunne self. smide et last active ned i db men ville det ikke være lidt bøvlet? - er der en anden måde jeg kan skrive mit statement på så jeg kun behøves at tjekke om brugerens id (som jeg skriver ud fra db) findes i listen. Fx.
foreach (DataRow item in dt.Rows) {
string online = ""; foreach (UserInfo listeItem in liste) { if (listeItem._id == Convert.ToInt32(item["fldid"])) { online = " Online";
} else { online = " Offline"; } }
litbrugere.Text += "" + item["fldbrugernavn"] + "" + online; } //men her ser man kun den sidste indloggede som " online"
if (liste.Contains(new UserInfo(Convert.ToInt32(item["fldid"]), item["fldbrugernavn"].ToString(), lastactive))) { online = " Online";}
Men det kræver jeg opretter en propertie til parameteret igen igen ^^ - hvordan kan jeg skrive det i mit statement så jeg trækker i min propertie i class istedet...
Jeg sammenligner hvad der er i List med det jeg udskriver fra db.
//Forkortet ned så meget som muligt foreach (DataRow item in dt.Rows) { string online =""; //er bruger id fra db i listen? - jeg ved ikke hvordan du ville gøre det? if (liste.Contains(new UserInfo(Convert.ToInt32(item["fldid"]), item["fldbrugernavn"].ToString()) { online = " Online";
} else if (!liste.Contains(new UserInfo(Convert.ToInt32(item["fldid"]), item["fldbrugernavn"].ToString()) { online = " Offline"; } //udskriver fra db + "online" variabel. Litbruger.Text = "" item["bruger"] + online;
}
Det er der så ingen problemer i, det fungerer - problemet er at jeg nu har et parameter mere i class (lastactive)som jeg også er tvunget til at definere i liste.Contains() - som her under:
Spørgsmålet er om du kunne skrive det på en anden måde så jeg kun behøves at definere om brugerens id er i listen - du kan se jeg også definere om brugernavn er i listen, hvilket heller ikke er nødvendigt lige i dette tilfælde. Som sagt så er dette første gang jeg arb med List og der er jo en masse måder at manipulere med List på som er fremmet.
1. lists.Any(x => x.Id == userId) ..hvad er x i denne sammenhæng for det lader ikke til at jeg kan få fat i et parameter eller propertie her?
(Det jeg mente var at hvorfor bruge en List når man kan manipulere det samme info frem og tilbage i en MySql db - ikke at jeg ikke foretrækker List i dette tilfælde.)
2. Når jeg opdatere brugerens lastactive ..i pageload i masterpage - hvordan ville du så skrive det uden at erstatte hele listen? Eller det kan vel ikke gøres på anden måde - hvor den pågældende bruger fjernes og lægges ind igen med nyt lastactive?
Smid din kode der ...der må være ting du ikke fortæller mig og hvad version af .NET ?
Du kan også gemme i Mysql hvem der er online, helt op til dig selv.
2. Jeg ville gøre.
var list = Application["list"] as List<UserInfo>; if(list == null) { throw new NullReferenceException("list burde ikek være null da den er sat i Global.asax"); }
var user = list.Single(a => a.UserId == someVaraibelSomHarUserId); user.LastActive = DateTime.Now;
1. Jeg kører framework 3.5 men det er nu mere fordi jeg ikke er blevet flyttet over til 4.0 servere endnu på surftown. ÅÅH... nu ser jeg det fungerer ..i dette øjeblik. liste.Any( x => x._id == Convert.ToInt32(item["fldid"] )) - dvs. x kan være hvad som helst - beklager... det var mig der ikke var konsekvent nok :D (forstår ikke helt pointen i pastie.org - at paste noget kode man vil vise frem?...og så nogle ret så sjove kommentarer :))
Det virker dog lidt bøvlet at smide ned i mysql db (men nemmere fordi jeg har arb meeget med det) - man kan vel sige at db er til for at håndtere staionært data - og ikke dette. Er glad for det du har lært om List - synes jeg har lært rigtig meget i denne tråd. 2. Mange tak.
=> betyder "goes to" og da du arbejder på en Liste af UserInfo, svarer "x" til et UserInfo object.
Any returnere true, hvis en af listens elementer er True, dvs den inderholder dit Id.
Pointen med pastie er at den laver syntax hightlighting, hvilket exp.dk ikke gør ... derfor er den dejlig at arbejde med.
Ligesom i en Skype/Msn/Gtalk chat ... lidt svært/umuligt at paste 200 linjer ... derfor er sådan nogle sites som pastie smarte.
Det bør også håndteres i memory og ikke i database. For mange ligegyldige read/writes til din DB for at se hvem der er online. At du så også lister offline brugere er måske lidt mærkeligt, men kommer selvf an på hvor listen skal vises.
Glad for at kunne hjælpe, men skal du have hjælp til andre ting, så opret nye spøgsmål, så er der chance for at andre også kan følge med i dem, da der jo nok ikke er nogen der kigger ind i gamle spørgsmål.
Tak for forklaringen der. Det er også en lang uhåndterlig tråd denne så jeg undlader at spørge om noget :) Jeg opretter nok en tråd om liste.RemoveAll() senere på aftenen.
Synes godt om
Ny brugerNybegynder
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.