Avatar billede pumpin Nybegynder
16. oktober 2006 - 23:32 Der er 14 kommentarer

Hit Counter som web custom control

Hej Eksperter

Jeg har for noget tid siden lavet mig en simpel counter som viser antalet af besøgte bruger på en given hjemme side. måden jeg har lavet det på er ved at bruge application variabels.

for lige at kaste lys over hvad jeg har lavet er min global.asax her:
void Application_Start(object sender, EventArgs e)
    {
        Application["Counter"] = 0;

    }

void Session_Start(object sender, EventArgs e)
    {
        lock (Application["Counter"])
        {
            Application["OnlineNow"] = Convert.ToInt32(Application["OnlineNow"]) + 1;
            if ((int)Application["Counter"] >= 5)
            {
                Counter.UpdateCount((int)Application["Counter"]);
                Application["Counter"] = 0;
            }
        }
        lock(Application["OnlineNow"])
        {
            Application["Counter"] = Convert.ToInt32(Application["Counter"]) + 1;
        }
       

    }

    void Session_End(object sender, EventArgs e)
    {
        lock (Application["OnlineNow"])
        {
            Application["OnlineNow"] = Convert.ToInt32(Application["OnlineNow"]) - 1;
        }
    }

Denne fil virker også super godt, men nu vil jeg gerne lave min counter som we web custom control istedet for. Men hvordan kommer jeg over det problem at jeg ikke har Session_start() , Session_End() til at incremente eller decremente min applications variabel ?

jeg har prøvet at lave en override på OnLoad men det event fires hver gang siden loader :(

kan man evt lave en override på Session_start og _End?

eller er der smarter måder at lave en hit counter når nu den skal ligge i en custom web control ??

På forhånd tak
Avatar billede mrbonus Novice
17. oktober 2006 - 00:51 #1
Det du gør er at override på OnLoad, og teste på om det er et postback der bliver lavet på siden

if (!this.IsPostBack)
{
    count++;
}
Avatar billede mrbonus Novice
17. oktober 2006 - 00:53 #2
Så undgår du at tælle op hver gang siden loades, men kun når brugeren går ind på siden på ny
Avatar billede pumpin Nybegynder
17. oktober 2006 - 10:22 #3
hvis brugeren så trykker F5 100 gange så tæller den jo 100 gange det skal den jo ikke.

Jeg har set nogle filer som hedder Global.asax.cs det er som reglt i tutorials.. jeg har også set at man kan linke en codebehind fil til sin global.asax og nedarve ser også ud til at være muligt men er der en smart måde jeg kan benytte det på, sådan at, slut brugeren ikke skal side og rode med sin global.asax fil i flere dage for at bruge min webcontrol ??

Eller skal skal jeg virkelig benytte mig af OnLoad, også ellers lave de onde tests for at se om brugeren har været på min side de sidste X antal timer / min  ( evt 20 min som min session)
Avatar billede pumpin Nybegynder
17. oktober 2006 - 12:20 #4
Dette er blot en ide.

Jeg ved der er noget der hedder en singelton, og at det er noget med at man altid får dem samme instance af sit object, kunne sådan en bruges i dette sammen hæng ?
Avatar billede mrbonus Novice
17. oktober 2006 - 16:34 #5
Singleton - Ja din counter skal være singleton, medmindre du laver en counter for hver enkelt person. Singleton er et object som alle brugere får den samme instans af, og det vil det jo være så vidt jeg kan høre på dig.

Jeg har ikke pillet så meget ved global.asax, så jeg ved ike om det kan lade sig gøre med den.

Du har  i hvert fald this.Session.IsNewSession til erstatning af session_start, men den med at dekrementere kender jeg ikke nogen nemme metoder til.

Men min ummidelbare måde at løse den på ville være at lave en en liste, med sessionIds, og tid, og så hver putte sessionid og tid ned i listen, samt tælle op, hvis sessionId'et ikke eksisterer i listen, og slette sessionId'erne hvis tiden overløber sessiontimeout, og tælle ned.
Avatar billede pumpin Nybegynder
19. oktober 2006 - 10:26 #6
jeg har et problem, jeg prøver at lave min counter som en control og så har jeg ikke mulighed fora t lave en singelton.. eller har jeg :) ?

Jeg er gået over til en ny ide gemme brugerens IP og timestamp i et dataset, og på den måde bestemmer jeg om brugeren har været der før, så er min ide at en gang om dagen pusher det dataset ud i en XML fil så har jeg nemlig IP og tid til evt sener brug ( statestik evt ) men nu ved jeg ikke det helt store om server controls, så hvad sker der engtlig når brugeren trækker mit "object" ud på sit stage... instancere VS2005 den for brugeren med NEW sådan at være bruger faktisk får en ny instanc af mit object og de på den måde arbejder på hvert sit dataset ?
Avatar billede mrbonus Novice
19. oktober 2006 - 16:28 #7
Singleton i C# laver du ved hjælp af en private static variable, så kommer det an på hvad du vil lave singleton, hvordan du skal bygge den komponent. Her er et lilel eksempel på hvordan du kan gøre.

public class Settings
{
    private static Settings settings = null;

    //private constructor so you have to use getInstance()       
    private Settings()
    {
    }

    public static Settings getInstance()
    {
        if (settings == null)
            settings = new Settings();

        return settings;
    }
}



ps. husk at tage højde for ikke thread safe objekter, da flere brugere nu vil arbejde i den samme instans
Avatar billede pumpin Nybegynder
20. oktober 2006 - 14:21 #8
Mr bonus jeg har kigget lidt på nettet omkring dem og synes ikke rigtig jeg kan gennem sku det, så je ghar valgt at gå ud fra iden om at gemme en liste med ip og tid.

jeg ved bare ikke om det er så smart igen. jeg poster lige koden hvis der nu skulle være andre med på en kigger.

namespace TestArea
{

    [DefaultProperty("Count")]
    [ToolboxData("<{0}:CounterControlNew runat=server></{0}:CounterControlNew>")]
    public class CounterControlNew : WebControl
    {
        private int _count;
        private DataTable _ipBank;
        private string _dumpFolder = "Counter/Charts";
        private string _counterFolder = "Counter/TotalCount";

        [Bindable(true), Category("Misc"), DefaultValue("Counter/TotalCount")]
        public string CounterFolder
        {
            get
            {
                if (!_counterFolder.EndsWith("/"))
                {
                    _counterFolder = _counterFolder.Insert(_counterFolder.Length, "/");
                }
                if (_counterFolder.StartsWith("/"))
                {
                    _counterFolder = _counterFolder.Remove(0, 1);
                }
                return _counterFolder;
            }
            set
            {
                _counterFolder = value;
            }
        }

        [Bindable(true), Category("Misc"), DefaultValue("Counter/Charts")]
        public string DumpFolder
        {
            get
            { 
                if(!_dumpFolder.EndsWith("/"))
                {
                    _dumpFolder = _dumpFolder.Insert(_dumpFolder.Length, "/");
                }
                if (_dumpFolder.StartsWith("/"))
                {
                    _dumpFolder = _dumpFolder.Remove(0, 1);
                }
                    return _dumpFolder;
            }
            set
            {
                _dumpFolder = value;
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            if (Context != null && !Page.IsPostBack)
            {
                Increment();
                CheckForDump();
            }
            base.OnLoad(e);
        }

        private void Increment()
        {
            //Opretter en ny datatabel eller henter en fra applications variabel.
            if (Page.Application["IpBank"] == null)
            {
                CreateNewIpBank();
            }
            else
            {
                _ipBank = (DataTable)Page.Application["IpBank"];
            }

            //henter Antalet af besøgende fra fil eller applications variabel.
            if (Page.Application["Counter"] == null)
            {
                _count = GetCounterFromFile();
            }
            else
            {
                _count = Convert.ToInt32(Page.Application["Counter"]);
            }

            //er der rows ? hvis ja tæller 1 op, hvis nej tæller 1 op og adder ip!
            if(_ipBank.Rows.Count>0)
            {
                _count++;
                foreach(DataRow row in _ipBank.Rows)
                {
                    //findes Ip'en i banken, hvis ja tæller en ned, hvis nej adder ip!
                    if (row["ip"].ToString() == GetIP())
                    {
                        _count--;
                    }
                    else
                    {
                        DataRow ipBankRow = _ipBank.NewRow();
                        ipBankRow["ip"] = GetIP();
                        ipBankRow["time"] = DateTime.Now.ToString();
                        _ipBank.Rows.Add(ipBankRow);
                    }
                }
            }
            else
            {
                _count++;
                DataRow ipBankRow = _ipBank.NewRow();
                ipBankRow["ip"] = GetIP();
                ipBankRow["time"] = DateTime.Now.ToString();
                _ipBank.Rows.Add(ipBankRow);
            }
           
            Page.Application.Lock();
            Page.Application["Counter"] = _count;
            Page.Application["IpBank"] = _ipBank;
            Page.Application.UnLock();
        }

        private void CheckForDump()
        {
            if (((DateTime)Page.Application["DumpDate"]).AddSeconds(2) < DateTime.Now)
            {
                DumpCounter();
                DumpIpBank();
            }
        }

        private void DumpIpBank()
        {
           

            if (Page.Application["IpBank"] != null)
            {
                CheckFolder(DumpFolder);
                _ipBank = (DataTable)Page.Application["IpBank"];
                string filename = HttpContext.Current.Server.MapPath(DumpFolder+((DateTime)Page.Application["DumpDate"]).ToShortDateString()+".xml");
                XmlTextWriter bankWriter = null;
                bankWriter = new XmlTextWriter(filename, null);

                try
                {
                    bankWriter.Formatting = Formatting.Indented;
                    bankWriter.Indentation = 6;
                    bankWriter.Namespaces = false;

                    bankWriter.WriteStartDocument();
                    bankWriter.WriteStartElement("Visitors");
                    foreach(DataRow row in _ipBank.Rows)
                    {
                        bankWriter.WriteStartElement("Visitor");

                        bankWriter.WriteStartElement("Ip");
                        bankWriter.WriteString(row["ip"].ToString());
                        bankWriter.WriteEndElement();

                        bankWriter.WriteStartElement("TimeStamp");
                        bankWriter.WriteString(row["time"].ToString());
                        bankWriter.WriteEndElement();

                        bankWriter.WriteEndElement();
                    }
                    bankWriter.WriteEndElement();
                    bankWriter.WriteEndDocument();
                    bankWriter.Flush();
                }
                catch (Exception ex)
                {
                    ex.Message.ToString();
                }
                finally
                {
                    if (bankWriter != null)
                    {
                        bankWriter.Close();
                    }
                }
               
            }//end if
            Page.Application.Remove("IpBank");
        }//end method

        private void DumpCounter()
        {
            if (Page.Application["Counter"] != null)
            {
                CheckFolder(CounterFolder);
                try
                {
                    StreamWriter CounterWriter;
                    CounterWriter = File.CreateText(HttpContext.Current.Server.MapPath(CounterFolder + "Counter.txt"));
                    CounterWriter.Write(_count);
                    CounterWriter.Close();
                    Page.Application.Remove("Counter");
                }
                catch (Exception) { }
            }
           
        }

        private int GetCounterFromFile()
        {
            CheckFolder(CounterFolder);
            //if (!File.Exists(HttpContext.Current.Server.MapPath(CounterFolder + "Counter.txt")));
            //{
            //    return 0;
            //}
           
            string temp = "";
            try
            {
                StreamReader CounterReader;
                CounterReader = File.OpenText(HttpContext.Current.Server.MapPath(CounterFolder + "Counter.txt"));
                temp = CounterReader.ReadLine();
                CounterReader.Close();
            }
            catch (Exception) { }
                return Convert.ToInt32(temp);

        }

        private void CheckFolder(string folder)
        {
            if (!System.IO.Directory.Exists(HttpContext.Current.Server.MapPath(folder)))
            {
                System.IO.DirectoryInfo di = System.IO.Directory.CreateDirectory(HttpContext.Current.Server.MapPath(folder));
            }
        }

        private string GetIP()
        {
            string hostAdress = Dns.GetHostName();
            IPHostEntry ipEntry = Dns.GetHostByName(hostAdress);
            IPAddress[] IpAddr = ipEntry.AddressList;

            return IpAddr[0].ToString();
        }

        private void CreateNewIpBank()
        {
            Page.Application["DumpDate"] = DateTime.Now;
            _ipBank = new DataTable();
            _ipBank.TableName = DateTime.Today.ToShortDateString();
            _ipBank.Columns.Add("ip", typeof(string));
            _ipBank.Columns.Add("time", typeof(string));

            Page.Application["IpBank"] = _ipBank;
        }
       
        protected override void RenderContents(HtmlTextWriter output)
        {
            output.RenderBeginTag(HtmlTextWriterTag.Table);
            output.RenderBeginTag(HtmlTextWriterTag.Tr);

            output.RenderBeginTag(HtmlTextWriterTag.Td);
            output.Write("Total Visit:");
            output.RenderEndTag();

            output.RenderBeginTag(HtmlTextWriterTag.Td);
            output.Write(_count);
            output.RenderEndTag();

            output.RenderEndTag();
            output.RenderEndTag();
        }
    }
}


i GetCounterFromFile virker denne if sætning ikke nogen der har en ide om why ?

//if (!File.Exists(HttpContext.Current.Server.MapPath(CounterFolder + "Counter.txt")));
            //{
            //    return 0;
            //}
Avatar billede pumpin Nybegynder
20. oktober 2006 - 14:26 #9
den med if sætningen bare glem den :) det ; skal self ikke værer der :)
Avatar billede mrbonus Novice
21. oktober 2006 - 11:30 #10
Jo det ser meget fornuftigt ud, nu ved jeg ikke hvor mange besøgende du får, men du bør nok lave noget synclock, eller en anden måde at beskytte skrivning til filerne, for at undgå fejl-læsning/skrivning, men ellers ser det meget godt ud
Avatar billede pumpin Nybegynder
30. oktober 2006 - 17:05 #11
hey mrbonus, jeg har ledt med lys og lygte efter noget info på hvad synclock er og hvordan jeg skulle implementere det.. men hvor er det præsist det kan gå galt jeg dumper jo kun filerne en gang i døgnet. ? ? post det evt som et svar så få du lige kastede nogle points efter dig som tak for supervisionen :D
Avatar billede mrbonus Novice
31. oktober 2006 - 08:52 #12
Hvad sker der, har lige lavet den store post, og den forsvandt bare da jeg trykkede send
Avatar billede mrbonus Novice
31. oktober 2006 - 08:53 #13
Nå men jeg vedlægger et eksempel her, og grundlæggende er det at hvis du har noget der ikke er threadsafe, så kan du manuelt lave objektet eller udførelsen threadsafe.

public class SyncLockExample
{
    private static object _syncRoot = new object();

    public SyncLockExample()
    {
    }

    public void writeToFile()
    {
        lock(_syncRoot)
        {
            //write to file
        }
    }

    public void readFromFile()
    {
        lock(_syncRoot)
        {
            //read from file
        }
    }
}
Avatar billede mrbonus Novice
31. oktober 2006 - 08:54 #14
skulle også have været et svar :(
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
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

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