myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns
» Datenschutzerklärung
» Impressum

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Knowledge Base » Artikel » [Tutorial] Windows Services mit C#
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

[Tutorial] Windows Services mit C#

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
egrath egrath ist männlich
myCSharp.de-Poweruser/ Experte

avatar-2119.jpg


Dabei seit: 24.07.2005
Beiträge: 871
Entwicklungsumgebung: MonoDevelop, NetBeans, Vi
Herkunft: Österreich / Steyr


egrath ist offline

[Tutorial] Windows Services mit C#

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Programmierung von Windows Services mit C#

In diesem kurzen Tutorial lernen Sie, wie sie ein Windows Service mittels der Programmiersprache C# und dem Microsoft.NET Framework erstellen. Ziel soll nicht sein, einen tiefen Einblick in die Gesamtarchitektur von Windows Services zu geben, sondern nur einen groben Überblick wie ein Grundlegendes Service implementiert wird.

Was sind Windows Services?

Ein Windows Service (im folgenden nur noch kurz "WS" genannt), ist prinzipiell nichts anderes, als eine Windows Applikation welche folgende Besonderheiten aufweist:

* Läuft auch dann, wenn kein Benutzer am System angemeldet ist.
* Interagiert im Normalfall nicht mit dem Desktop des Benutzers.
* Wird vom Windows Service Manager gestartet, angehalten und gestoppt.

Der Sinn eines WS liegt darin, dass ein System Dienste zur Verfügung stellen kann, ohne dass ein Benutzer dieses explizit starten muss.

Die Entwicklung eines WS

Wir werden in diesem Tutorial ein WS entwickeln, welches folgende Aufgaben übernimmt:

* An einem Netzwerkport horchen
* Für jede Anfrage auf diesem einen neuen Thread starten und das aktuelle Datum und Uhrzeit zurückschreiben

Der erste Schritt besteht darin, das Grundgestell unseres WS zu erstellen. Dies sieht in unserem Fall folgendermassen aus:

C#-Code:
public class TestWinService : ServiceBase
{
    private NetworkDateServer m_DateServer;

    public static void Main( string[] args )
    {
        System.ServiceProcess.ServiceBase.Run( new TestWinService() );
    }

    protected override void OnStart( string[] args )
    {
        m_DateServer = new NetworkDateServer();
        Thread dateServerThread = new Thread( new ThreadStart( m_DateServer.StartServer ));
        dateServerThread.Start();
    }

    protected override void OnStop()
    {
        m_DateServer.StopServer();
    }
}

Obige Klasse dient als Einsprungspunkt unseres WS und ist für folgende Aktionen zuständig:

* Starten des Service Prozesses
* Behandeln der Events "OnStart" und "OnStop"

Wird vom Service Manager das WS gestartet, so wird das Event "OnStart" ausgelöst, welches in unserem Fall dafür zuständig ist, die Klasse "NetworkDateServer" zu instanziieren und diesen Server zu starten. Analog wird beim beenden durch den Service Manager das Event "OnStop" ausgelöst, welches den Server beendet. Wie dieser Server aufgebaut ist, sehen wir untenstehend:

C#-Code:
public class NetworkDateServer
{
    private TcpListener m_TcpListener;
    private bool m_StopServer;

    public void StopServer()
    {
        m_StopServer = true;
    }

    public void StartServer()
    {
        m_StopServer = false;
        m_TcpListener = new TcpListener( IPAddress.Any, 27200 );
        m_TcpListener.Start();

        while( ! m_StopServer )
        {
            TcpClient client = m_TcpListener.AcceptTcpClient();
            Thread dateSender = new Thread( new ParameterizedThreadStart(( new DateSender()).SendDateToClient ));
            dateSender.Start( client );
        }

        m_TcpListener.Stop();
    }

    internal class DateSender
    {
        public void SendDateToClient( object client )
        {
            TcpClient networkClient = ( TcpClient ) client;
            NetworkStream networkStream = networkClient.GetStream();

            byte[] dateBuffer = System.Text.Encoding.ASCII.GetBytes( DateTime.Now.ToString() );
            networkStream.Write( dateBuffer, 0, dateBuffer.Length );

            networkStream.Close();
            networkClient.Close();
        }
    }
}

Im Endeffekt realisiert die Klasse "NetworkDateServer" einen Multi-Threaded Server, welcher am Port 27200 horcht und für jeden sich verbindenden Client einen neuen Thread startet, welcher anschliessen das aktuelle Datum und Uhrzeit an diesen schickt.

Da diese beiden Klassen schon unser gesamtes WS ausmachen, sehen wir abschliessend im nächsten Kapitel wie man die Installationsroutine programmatisch entwickeln kann.

Die Installation eines WS

Klassischerweise wird die Installation eines WS auf zwei verschiedene Arten durchgeführt:

* Per Hand durch erstellen der notwendigen Registry Einträge
* Vom Installer der Applikation

Wir werden den Schritt des Applikationsinstallers wählen und können dies mit .NET eigenen Bordmitteln relativ schnell und elegant realisieren. Dazu fügen wir zu unserem WS folgende Klasse hinzu:

C#-Code:
[RunInstaller( true )]
public class TestWinInstaller : Installer
{
    private ServiceInstaller m_ThisService;
    private ServiceProcessInstaller m_ThisServiceProcess;

    public TestWinInstaller()
    {
        m_ThisService = new ServiceInstaller();
        m_ThisServiceProcess = new ServiceProcessInstaller();

        m_ThisServiceProcess.Account = ServiceAccount.NetworkService;
        m_ThisService.ServiceName = "Simple Test Service";
        m_ThisService.StartType = ServiceStartMode.Manual;

        Installers.Add( m_ThisService );
        Installers.Add( m_ThisServiceProcess );
    }
}

Wenn unser WS als kompilierte EXE Datei vorliegt können wir diese dann durch einen simplen aufruf von "installutil dateiname.exe" installieren. Dies funktioniert, weil wir das Attribut "RunInstaller" angegeben haben und das "installutil" mittels Reflection nachsieht welche Klasse dieses besitzt, diese dann lädt und ausführt.

Kompletter Sourcecode des WS inklusive Installers

C#-Code:
using System;
using System.Configuration.Install;
using System.ComponentModel;
using System.ServiceProcess;
using System.IO;
using System.Net.Sockets;
using System.Net;
using System.Threading;

[RunInstaller( true )]
public class TestWinInstaller : Installer
{
    private ServiceInstaller m_ThisService;
    private ServiceProcessInstaller m_ThisServiceProcess;

    public TestWinInstaller()
    {
        m_ThisService = new ServiceInstaller();
        m_ThisServiceProcess = new ServiceProcessInstaller();

        m_ThisServiceProcess.Account = ServiceAccount.NetworkService;
        m_ThisService.ServiceName = "Simple Test Service";
        m_ThisService.StartType = ServiceStartMode.Manual;

        Installers.Add( m_ThisService );
        Installers.Add( m_ThisServiceProcess );
    }
}

public class TestWinService : ServiceBase
{
    private NetworkDateServer m_DateServer;

    public static void Main( string[] args )
    {
        System.ServiceProcess.ServiceBase.Run( new TestWinService() );
    }

    protected override void OnStart( string[] args )
    {
        m_DateServer = new NetworkDateServer();
        Thread dateServerThread = new Thread( new ThreadStart( m_DateServer.StartServer ));
        dateServerThread.Start();
    }

    protected override void OnStop()
    {
        m_DateServer.StopServer();
    }
}

public class NetworkDateServer
{
    private TcpListener m_TcpListener;
    private bool m_StopServer;

    public void StopServer()
    {
        m_StopServer = true;
    }

    public void StartServer()
    {
        m_StopServer = false;
        m_TcpListener = new TcpListener( IPAddress.Any, 27200 );
        m_TcpListener.Start();

        while( ! m_StopServer )
        {
            TcpClient client = m_TcpListener.AcceptTcpClient();
            Thread dateSender = new Thread( new ParameterizedThreadStart(( new DateSender()).SendDateToClient ));
            dateSender.Start( client );
        }

        m_TcpListener.Stop();
    }

    internal class DateSender
    {
        public void SendDateToClient( object client )
        {
            TcpClient networkClient = ( TcpClient ) client;
            NetworkStream networkStream = networkClient.GetStream();

            byte[] dateBuffer = System.Text.Encoding.ASCII.GetBytes( DateTime.Now.ToString() );
            networkStream.Write( dateBuffer, 0, dateBuffer.Length );

            networkStream.Close();
            networkClient.Close();
        }
    }
}

[EDIT=herbivore]Siehe auch  Debuggen von Windows-Dienstanwendungen[/EDIT]
11.05.2006 08:00 Beiträge des Benutzers | zu Buddylist hinzufügen
norman_timo norman_timo ist männlich
myCSharp.de-Poweruser/ Experte

avatar-1775.jpeg


Dabei seit: 13.07.2004
Beiträge: 4.506
Entwicklungsumgebung: .NET 2.0/3.5 und VS2005/VS2008
Herkunft: Wald-Michelbach (Odw)


norman_timo ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo egrath,

ich finde den Artikel sehr gut, da viele Programmierer den guten alten WS doch vergessen haben ;-)

Auch dass eine Installationsroutine mit beschrieben wird, finde ich sehr gut.

Also 1+ ;-)

Gruß
Norman-Timo
11.05.2006 08:42 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
.Kai .Kai ist männlich
myCSharp.de-Poweruser/ Experte

avatar-1836.gif


Dabei seit: 01.02.2005
Beiträge: 1.130


.Kai ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Auch von mir: Daumen hoch Daumen hoch
Sehr schön geschrieben.
11.05.2006 08:53 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Krieger
myCSharp.de-Mitglied

Dabei seit: 15.05.2006
Beiträge: 80
Entwicklungsumgebung: VS.Net 2008 Team System
Herkunft: Rosenheim


Krieger ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Japp das hat mir jetzt auch geholfen, denn ein "Nicht Debug Build" von meinen IRC Services schreit ja geradezu nach WS smile Schön einfach, danke dir auch von mir: Daumen hoch Daumen hoch Daumen hoch Daumen hoch Daumen hoch 5 / 5 Gummipunkte ^^
15.05.2006 16:49 Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegt mehr als ein Monat.
Thorsten1983 Thorsten1983 ist männlich
myCSharp.de-Mitglied

Dabei seit: 14.06.2005
Beiträge: 147


Thorsten1983 ist offline MSN-Passport-Profil von Thorsten1983 anzeigen

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

also egrath,

ich muss auch sagen dass der Artikel sehr gut ist, ich selbst habe schon mehrere Services erstellt die mehr oder minder trivial waren. Aber ich denke mal mit deinem Tut werden es Neueinsteiger im Bereich der Dienstentwicklung um einiges einfacher haben.


Daumen hoch Daumen hoch
14.07.2006 09:11 Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 2 Monate.
Schakal Schakal ist männlich
myCSharp.de-Mitglied

avatar-74.gif


Dabei seit: 16.11.2005
Beiträge: 37
Entwicklungsumgebung: Notepad++, VisualStudio2005 Pr
Herkunft: VS-Villingen / Germany


Schakal ist offline Füge Schakal Deiner Kontaktliste hinzu YIM-Screenname von Schakal: CS_Schakal

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Nicht schlecht Herr Specht...

schöner Artikel. Wenn ich mal Zeit kann poste ich gern noch einen Teil über das Remoting mit dem Service und vorallem die ServiceController-Class.

In diesem Sinne nice Work...
11.10.2006 13:59 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
dr4g0n76
myCSharp.de-Poweruser/ Experte

avatar-1768.jpg


Dabei seit: 07.07.2005
Beiträge: 2.875
Entwicklungsumgebung: SharpDevelop/VS.NET
Herkunft: Deutschland


dr4g0n76 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Wie mache ich das mit dem Installer in VS.Net 2003?

Muss es leider mit der Version machen, da gibt's aber kein
StartType
ServiceName
DisplayName
?

Ok [RunInstallerAttribute(true)] anstatt [RunInstallertrue)]
bringts anscheinend.

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von dr4g0n76 am 30.10.2006 18:03.

30.10.2006 17:20 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Jabi
myCSharp.de-Mitglied

Dabei seit: 02.09.2006
Beiträge: 222


Jabi ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

hallo eine frage ....

kann man in vs 2005 std edition kein windows service erstellen oder muss man da zusätzlich was installiern denn ich finde keinen projekt typ dafür ?
03.11.2006 09:15 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
egrath egrath ist männlich
myCSharp.de-Poweruser/ Experte

avatar-2119.jpg


Dabei seit: 24.07.2005
Beiträge: 871
Entwicklungsumgebung: MonoDevelop, NetBeans, Vi
Herkunft: Österreich / Steyr

Themenstarter Thema begonnen von egrath

egrath ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

das Template "Windows Service" ist erst ab der Professional Edition enthalten - das fehlen dieser sollte dich aber trotzdem nicht davon abhalten einen Service zu erstellen (Empty Project)

Grüsse, Egon
03.11.2006 21:21 Beiträge des Benutzers | zu Buddylist hinzufügen
mitti mitti ist männlich
myCSharp.de-Mitglied

Dabei seit: 12.10.2006
Beiträge: 253
Herkunft: Österreich


mitti ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Guter Artikel!
04.11.2006 20:17 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
cx°
myCSharp.de-Mitglied

avatar-1921.jpg


Dabei seit: 18.05.2005
Beiträge: 190


cx° ist offline

Befehl an einen Windows Service senden

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Befehl an diesen Windows Service senden

Möchte man nun einen Befehl an diesen Windows Service senden, kann man das auf sehr einfache Art mit dem Überschreiben der Methode OnCustomCommand [ MSDN: ServiceBase.OnCustomCommand-Methode] bewerkstelligen. Egon's Code wird wie folgt erweitert:

C#-Code:
public class TestWinService : ServiceBase
{
    private NetworkDateServer m_DateServer;

    public static void Main( string[] args )
    {
        System.ServiceProcess.ServiceBase.Run( new TestWinService() );
    }

    protected override void OnStart( string[] args )
    {
        m_DateServer = new NetworkDateServer();
        Thread dateServerThread = new Thread( new ThreadStart( m_DateServer.StartServer ));
        dateServerThread.Start();
    }

    protected override void OnStop()
    {
        m_DateServer.StopServer();
    }

    protected override void OnCustomCommand(int command) // <---- überschreiben
    {
        switch (command)
        {
              case 150: // z.B. DateServer starten
                 // ...
                 break;

              case 151: // DateServer stoppen
                 m_DateServer.StopServer();
                 break;
        }
     }
}

Jetzt können die Befehle '150' und '151' von einem anderen Programm abgesetzt werden, um den DateServer zu starten/stoppen. Der Windows Service läuft weiter. Ein mögliches Programm könnte eventl. so aussehen:

C#-Code:
using System.ServiceProcess;

public partial class MyServiceGUI : Form
{
        ServiceController sc;

        public MyServiceGUI()
        {
              sc = new ServiceController("Simple Test Service"); // festgelegt in der Klasse [I]TestWinInstaller[/I]

              sc.ExecuteCommand(151);   // -> Auswertung in OnCustomCommand des Services; hier [I]DateServer[/I] stoppen
        }
}

Es gibt natürlich noch andere Möglichkeiten (Remoting,...), um Befehle an Windows Services zu senden, dies scheint mir aber der einfachste.

Gruß cx°
17.11.2006 14:16 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegt mehr als ein Monat.
pgloor
myCSharp.de-Mitglied

Dabei seit: 06.12.2005
Beiträge: 2
Entwicklungsumgebung: Visual Studio 2005


pgloor ist offline

Gute Ergänzung

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Daumen hoch Super Artikel mit toller Ergänzung von cx°

Kann nur Gratulieren! smile
19.12.2006 16:57 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 6 Monate.
Leia2011 Leia2011 ist weiblich
myCSharp.de-Mitglied

Dabei seit: 15.06.2007
Beiträge: 17


Leia2011 ist offline

Windows Dienst mit .net 2003

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo, ich habe eine Frage an dr4g0n76 gestellt, zu der er gern das Projekt posten möchte:
Hier unser Dialog:

Zitat:
-----Ursprüngliche Nachricht-----
Nachricht von: Leia2011
Gesendet: 03.07.2007 13:24
An: dr4g0n76
Betreff: Dein Beitrag im Forum: Community-Index » Diskussionsforum » Knowledge Base » Artikel » [Tutorial] Wi

Hi!

hast du rausgefunden, welche Namespaces und welche Sachen man beachten muss, wenn man einen Windows - Dienst mit VS 2003 erstellen möchte?
Ich finde leider nur Beispiele fürs .net Framework 2.0.

Meine Anwendung darf aber unbedingt nur 1.1 verwenden.

Kannst du mir da vllt ein paar Tipps geben?
Dafür wäre ich sehr dankbar.

Zitat:
Nachricht von dr4g0n76 vom 03.07.2007 15:15:

Unbedingt diese beiden Verweise einbinden:

System.Configuration.Install;
System.ServiceProcess;

sonst läufts nicht.

Hast Du ne Windows-Dienst-Vorlage?

Oder schreib Die Frage ins Forum, vielelicht am besten angehängt beim Artikel Thread zu den Windows-Services, dann könnte ich die Projekt-Vorlage hinzufügen.

Gruss, dr4g0n76
05.07.2007 14:24 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
dr4g0n76
myCSharp.de-Poweruser/ Experte

avatar-1768.jpg


Dabei seit: 07.07.2005
Beiträge: 2.875
Entwicklungsumgebung: SharpDevelop/VS.NET
Herkunft: Deutschland


dr4g0n76 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

So, dieser Dienst sollte auch in VS 2003 funktionieren, bzw. das Grundgerüst.


Dateianhang:
unknown Dienst.rar (20,27 KB, 2.025 mal heruntergeladen)
05.07.2007 15:10 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 7 Monate.
haxXxy haxXxy ist männlich
myCSharp.de-Mitglied

avatar-394.gif


Dabei seit: 10.07.2007
Beiträge: 212
Entwicklungsumgebung: vs 6, 2005, 2008 prof,#develop
Herkunft: Köln


haxXxy ist offline MSN-Passport-Profil von haxXxy anzeigen

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Daumen hoch
25.02.2008 09:58 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
chrisbradyat chrisbradyat ist männlich
myCSharp.de-Mitglied

Dabei seit: 19.02.2007
Beiträge: 26
Entwicklungsumgebung: Visual Studio 2008 Prof.
Herkunft: Linz


chrisbradyat ist offline

Beliebiges Programm als Dienst einrichten

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Kommt zwar von der "AdminSeite", könnte aber für den ein oder anderen von Interesse
sein.

Create your own user-defined services Windows NT/2000/XP/2003
 http://www.tacktech.com/display.cfm?ttid=197
23.03.2008 10:13 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 7 Jahre.
OlafSt OlafSt ist männlich
myCSharp.de-Mitglied

Dabei seit: 02.05.2011
Beiträge: 61
Entwicklungsumgebung: VS 2015 Community
Herkunft: HH


OlafSt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Mit VS2013 Community und gegen .NET4.5 muß man eine Kleinigkeit beachten. Denn: Der Namespace "System.Configuration.Install" scheint gar nicht mehr zu existieren geschockt Die MSDN-Hilfe von Microsoft führt auf eine völlig falsche Fährte (man ist geneigt zu glauben, das sei .NET3.5 und älter).

Tatsächlich muß man zunächst einen Verweis auf "System.Configuration.Install" hinzufügen, dann hat man auch einen ".Install"-Namespace und auch eine Klasse "Installer".
02.03.2016 10:42 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
p!lle
myCSharp.de-Mitglied

avatar-3556.jpg


Dabei seit: 22.02.2007
Beiträge: 987
Entwicklungsumgebung: Visual Studio (Community) 2017


p!lle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von OlafSt:
Denn: Der Namespace "System.Configuration.Install" scheint gar nicht mehr zu existieren geschockt

Zitat von OlafSt:
Tatsächlich muß man zunächst einen Verweis auf "System.Configuration.Install" hinzufügen

verwundert
Ohne den Rest des Themas gelesen zu haben, die Aussagen widersprechen sich doch völlig?
Das man einen Verweis auf fehlende .dll's hinzufügen muss, ist doch vollkommen normal...

Siehe auch:  [FAQ] CS0234 / CS0246 - Der Typ- oder Namespacename "Foo" konnte nicht gefunden werden

Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von p!lle am 02.03.2016 11:16.

02.03.2016 11:01 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 13 Jahre.
Der letzte Beitrag ist älter als 3 Jahre.
Antwort erstellen


© Copyright 2003-2019 myCSharp.de-Team | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 20.06.2019 10:26