Announcement

Collapse
No announcement yet.

Windows Dienst mit Timer

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Windows Dienst mit Timer

    Hi,

    Ich komme nicht so ganz zurecht mit einem Timer in einem Windows Service.
    Einige Hinweise habe ich bereits im Netz gefunden, aber bei mir stimmt irgendetwas nicht.

    Mein Aktueller Stand:
    Code:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    using System.Timers;
    
    namespace WindowsServiceTest
    {
        public partial class Service1 : ServiceBase
        {
    
            const string ServiceLogFile = @"C:\Users\me\Documents\ServiceTestLog.txt";
            private Timer timer1;
    
            public Service1()
            {
                InitializeComponent();
            }
    
            protected override void OnStart(string[] args)
            {
                try {
                    System.IO.File.Create(ServiceLogFile);
                    timer1 = new Timer();
                    timer1.Enabled = true;
                    timer1.Interval = 5000;
                    timer1.AutoReset = true;
                    timer1.Elapsed += new ElapsedEventHandler(timer_Elapsed);
                    timer1.Start();
                } catch(Exception e) {
                    System.IO.File.AppendAllText( ServiceLogFile, e.ToString() + "\r\n\r\n" );
                }
            }
    
            protected override void OnStop()
            {
                try {
    
                    timer1.Stop();
                    System.IO.File.Delete(ServiceLogFile);
    
                } catch(Exception e) {
                    System.IO.File.AppendAllText(ServiceLogFile, e.ToString() + "\r\n\r\n");
                }
            }
    
            private void timer_Elapsed( object sender, ElapsedEventArgs e )
            {
    
                try {
    
                    System.IO.File.AppendAllText(ServiceLogFile, DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss") + "\r\n");
    
                } catch(Exception ex) {
                    System.IO.File.AppendAllText(ServiceLogFile, ex.ToString() + "\r\n\r\n");
                }
    
            }
    
        }
    }
    In der Basis-Konfiguration ohne Timer funktioniert es wie gewünscht. Starten und Stoppen des Dienstes ist kein Problem.

    Mit dem Timer allerdings nicht.
    Wie zu erkennen ist, soll der Timer im Test erstmal nur dafür sorgen, dass alle 5 Sekunden etwas in das ServiceLogFile geschrieben wird.
    Das passiert aber nicht. Auch die catch()-Blöcke scheinen nicht ausgeführt zu werden, zumindest wird nichts in die Datei geschrieben.

    Beim Beenden des Dienstes mit Timer bekomme ich zudem auch immer die Meldung:
    service-stop-error.jpg

    Ich hätte jetzt zumindest vermutet oder gehofft, dass mir die catch()-Blöcke etwas Aussage darüber bringen, aber es passiert leider nichts.
    Ich bin mir relativ sicher, dass das mit dem Timer zu tun haben muss, weil ich wie gesagt ohne Timer keine Probleme habe und er dann auch tut, was er soll.

    Ich hatte auch den Timer ganz am Anfang aus der Toolbox gezogen ( System.Timers.Timer ) und auch damit schon das gleiche Problem.
    bei meiner Suche im Netz habe ich halt die Variante wie oben öfter gesehen, habe aber damit das gleiche Problem.

    Sieht jemand von euch, was noch falsch sein oder wo ich schauen könnte?

    Danke
    PHP rocks!
    Eine Initiative der PHP Community

  • #2
    Hallo,

    ja das hat mit dem Timer zu tun. Für weitere Diagnostik kannst du schauen was im Eventlog (von Windows) drin steht.

    In .NET gibt es (leider) mehrere Timer (da hat wohl jede Abteilung gem. NIH-Syndrom ihren eigenen geschrieben) und der von dir verwendete ist der Timer Class (System.Timers), welcher von Component erbt und somit einen UI-Bezug hat. Windows-Dienste haben (standardmäßig) keinen UI-Bezug und somit kracht es irgendwo in der Ausführung (-> siehe Eventlog).

    Abhilfe schafft die Verwendung eine anderen Timers, nämlich den Timer Class (System.Threading).

    mfG Gü
    "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

    Comment


    • #3
      Das ist ja interessant. Den Unterschied zwischen System.Windows.Forms.Timer und System.Timers.Timer hatte ich so wie beschrieben verstanden.
      Alle Beispiele, auch die, die ich auf stackoverflow gefunden habe, arbeiten mit dem System.Timers.Timer, genau wie ich. Selbst in einem Youtube-Tutorial konnte ich ja sehen, dass es funktioniert hat.

      Komisch, aber ich teste das mal mit dem Threading-Timer, danke für die Info!
      PHP rocks!
      Eine Initiative der PHP Community

      Comment


      • #4
        Irgendwie will das bei mir nicht, ich übersehe sicher etwas entscheidendes?

        Der Dienst lässt sich fehlerfrei starten und beenden, allerdings werden keine Informationen in die Datei geschrieben, weder die erwarteten Testausgaben, noch irgendwelche Exception-Messages.
        Was ich auch merkwürdig finde ist, dass das Delete in OnStop() auch keine Wirkung mehr zeigt, ohne Timer klappt das problemlos.

        Mein aktueller Stand:
        Code:
        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.Data;
        using System.Diagnostics;
        using System.Linq;
        using System.ServiceProcess;
        using System.Text;
        using System.Threading;
        
        namespace WindowsServiceTest
        {
            public partial class Service1 : ServiceBase
            {
        
                const string ServiceLogFile = @"A:\WindowsServiceTest\ServiceStarted.txt";
                private System.Threading.Timer timer1;
        
        
                public Service1() {
        
                    InitializeComponent();
        
                }
        
                protected override void OnStart(string[] args) {
        
                    try {
        
                        System.IO.File.Create(ServiceLogFile);
        
                        timer1 = new System.Threading.Timer( TestLog );
        
                        if (!timer1.Change(5000, 5000)) {
        
                            System.IO.File.AppendAllText(ServiceLogFile, "Timer.Change responds false\r\n\r\n");
        
                        }
        
                    } catch(Exception e) {
        
                        System.IO.File.AppendAllText( ServiceLogFile, e.ToString() + "\r\n\r\n" );
        
                    }
        
                }
        
                protected override void OnStop() {
        
                    try {
        
                        System.IO.File.Delete(ServiceLogFile);
        
                    } catch(Exception e) {
        
                        System.IO.File.AppendAllText(ServiceLogFile, e.ToString() + "\r\n\r\n");
        
                    }
        
                }
        
                private void TestLog( object sender ) {
        
                    try {
        
                        System.IO.File.AppendAllText(ServiceLogFile, DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss") + "\r\n");
        
                    } catch(Exception ex) {
        
                        System.IO.File.AppendAllText(ServiceLogFile, ex.ToString() + "\r\n\r\n");
        
                    }
        
                }
        
            }
        }
        PHP rocks!
        Eine Initiative der PHP Community

        Comment


        • #5
          Hallo,

          was steht denn in der Ereignisanzeige (siehe oben)?

          Wie installierst du den Service (ServiceInstaller-Klasse) und mit welchem Benutzer läuft der Dienst? Hat der Dienst Zugriff auf das Dateisystem....

          mfG Gü
          "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

          Comment


          • #6
            Hi, bin morgen erst wieder vor der Kiste, läuft im Büro.
            Also in der Ereignisanzeige stand nur ein WindowsError ohne Details, kann gerne auch mal die erzeugte XML morgen hier reinhängen, wenn das hilft?

            Ich habe einen Installer zugefügt ( serviceProcessInstaller1 und serviceInstaller1, heißen die Komponenten dann, meine ich? ). Installieren tue ich das allerdings per Developer CMD mit installutil. CMD und Visual Studio laufen natürlich im Administrator-Modus.

            Zugriff auf das Dateisystem ist da, er legt ja auch die Datei im OnStart() an und ohne Timer wird ja auch im OnStop() das Löschen der Datei durchgeführt.
            Er muss irgendwo ein dickes Problem haben, weil er scheinbar nicht mal mehr das OnStop() erreicht oder zumindest nicht mehr ausführt, wenn ich den Dienst beende.

            Debugging habe ich auch versucht. Wenn ich einen Breakpoint in der Methode TestLog() setze, meldet er mir, dass der Bereich überhaupt nicht erreicht wird.
            Auf die Abfrage ob timer1.Change() true oder false liefert bekomme ich auch keine Infos in die Datei. Für mich sieht es so aus, als ob er nach dem Erstellen der Datei wegbricht?

            Detailliertere Infos kann ich dann leider erst morgen liefern.

            Danke für Deine Unterstützung!
            PHP rocks!
            Eine Initiative der PHP Community

            Comment


            • #7
              Ich würde mal das File schreiben durch eine ausprogrammierte eigene Variante die mit einem Lock geschützt ist ersetzen. Du machst direkten Dateizugriff aus einem Service heraus der spätestens nach dem Einsatz des Threading Timers potentiell konkurierende Filezugriffe macht. AppendAllText macht jeweils wieder einen eigenen exclusiven Handle auf die Datei auf. Wenn Delete nicht geht schreit es gerade zu danach das du selber noch ein Handle auf die Datei hältst. Leider ist die File Klasse nur mäßig vertrauenswürdig im in Multithreading Umgebung die kann man dort nicht einfach unreflektiert verwenden. Also ersetze die File Klasse durch einen eigenen Filestream, denn kannst du zum appenden eigentlich auch erstmal einfach offen halten und gezielt flushen. Das appenden dann durch einen Lock schützen das das auch schön nacheinander passiert. Nebenbei wenn beim benutzen einen Files ein Problem auftritt das Problem mit dieser Datei genau in diese Datei schreiben zu wollen ist eher nicht zielführend Ich würde das dann z.B. ins Windows EventLog schreiben.

              Comment


              • #8
                Hi Ralf, da hast Du recht, das hätte ich mal wie in den Beispielen machen sollen. Die machen das nämlich mit Streams, ich habe nur auf die Schnelle zu File gegriffen. Das ist der einzige Unterschied zu den Beispielen.
                Das werde ich mal von vorne beginnen und mit Streams und LOCK testen. Danke für den Tipp.
                PHP rocks!
                Eine Initiative der PHP Community

                Comment


                • #9
                  Vielen Dank, so klappt es jetzt. Ich entschlacke das Beispiel nochmal und pack das dann hier rein, falls jemand mal ähnliches Problem hat und über diesen Thread stolpert.

                  Gruß
                  Arne
                  PHP rocks!
                  Eine Initiative der PHP Community

                  Comment

                  Working...
                  X