J'ai créé un service Windows appelé ProxyMonitor et je suis actuellement au stade où le service est installé et désinstallé comme je le souhaite.
Donc, j'exécute l'application comme suit:
C:\\Windows\\Vendor\\ProxyMonitor.exe /install
C'est assez explicite, puis je suis arrivé à services.msc
et je lance le service, mais lorsque je le fais, je reçois le message suivant:
Le service de surveillance proxy sur l'ordinateur local a démarré puis s'est arrêté. Certains services s'arrêtent automatiquement s'il n'y a pas de travail à faire. Par exemple, les services de journalisation et d'alertes de performance
Mon code ressemble à ceci:
public static Main(string[] Args)
{
if (System.Environment.UserInteractive)
{
/*
* Here I have my install logic
*/
}
else
{
ServiceBase.Run(new ProxyMonitor());
}
}
Et puis dans la classe ProxyMonitor, j'ai:
public ProxyMonitor()
{
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
ProxyEventLog.WriteEntry("ProxyMonitor Started");
running = true;
while (running)
{
//Execution Loop
}
}
et onStop()
Je viens de changer la variable running
en false
;
Que devrais-je faire pour rendre le service actif en permanence, tout comme je devrais surveiller le réseau dont j'ai besoin pour suivre les modifications, etc.
Mise à jour: 1
protected override void OnStart(string[] args)
{
base.OnStart(args);
ProxyEventLog.WriteEntry("ProxyMonitor Started");
Thread = new Thread(ThreadWorker);
Thread.Start();
}
Dans la ThreadWorker
j'ai ProxyEventLogger.WriteEntry("Main thread entered")
qui ne se fait pas virer.
Le rappel OnStart()
doit être renvoyé à temps, vous voudrez donc lancer un fil où tout votre travail sera effectué. Je recommanderais d'ajouter les champs suivants à votre classe:
using System.Threading;
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
private Thread _thread;
Le champ _thread
contiendra une référence à l'objet System.Threading.Thread
que vous avez créé dans le rappel OnStart()
. Le champ _shutdownEvent
contient une construction d'événement de niveau système qui sera utilisée pour indiquer au thread de cesser de s'exécuter à la fermeture du service.
Dans le callback OnStart()
, créez et démarrez votre thread.
protected override void OnStart(string[] args)
{
_thread = new Thread(WorkerThreadFunc);
_thread.Name = "My Worker Thread";
_thread.IsBackground = true;
_thread.Start();
}
Vous avez besoin d’une fonction nommée WorkerThreadFunc
pour que cela fonctionne. Il doit correspondre à la signature System.Threading.ThreadStart
delegate.
private void WorkerThreadFunc()
{
}
Si vous ne mettez rien dans cette fonction, le thread démarrera puis s’arrêtera immédiatement. Vous devez donc y insérer une logique qui le maintient en vie pendant que vous travaillez. C'est ici que le _shutdownEvent
est utile.
private void WorkerThreadFunc()
{
while (!_shutdownEvent.WaitOne(0)) {
// Replace the Sleep() call with the work you need to do
Thread.Sleep(1000);
}
}
La boucle while vérifie la ManualResetEvent
pour voir si elle est "définie" ou non. Puisque nous avons initialisé l'objet avec false
ci-dessus, cette vérification renvoie false. Dans la boucle, nous dormons pendant 1 seconde. Vous voudrez remplacer ceci par le travail que vous devez faire - surveiller les paramètres de proxy, etc.
Enfin, dans le callback OnStop()
de votre service Windows, vous souhaitez signaler au thread de s’interrompre. C'est facile en utilisant le _shutdownEvent
.
protected override void OnStop()
{
_shutdownEvent.Set();
if (!_thread.Join(3000)) { // give the thread 3 seconds to stop
_thread.Abort();
}
}
J'espère que cela t'aides.
Vous devez quitter votre gestionnaire OnStart
pour que le contrôleur de service réalise que votre service a réellement démarré. Pour que tout fonctionne comme vous le souhaitez, vous pouvez démarrer une minuterie qui se déclenche à intervalles réguliers et qui se déclenche une fois à l’autre.
Modifier:
Essayez de placer un System.Diagnostics.Debugger.Launch () dans votre OnStart
pour voir ce qui se passe (et mettez un point d'arrêt dans ThreadWorker
). Je recommanderais de placer ceci dans #if DEBUG
pour m'assurer qu'il ne soit pas déployé.
Je viens aussi de réaliser que vous ne donnez pas à votre Thread
un nom:
Thread myThread = new Thread(ThreadWorker);
myThread.Start();
Certainement pas l'ajout d'une boucle while
dans la méthode OnStart
. Cela indiquera au système d'exploitation que le service n'a pas démarré car il n'a pas pu sortir en toute sécurité de la méthode OnStart
. Je crée généralement une Timer
qui est activée dans la méthode OnStart
. Ensuite, dans la méthode Ticks
, j'appelle la méthode nécessaire pour que l'application s'exécute.
Vous pouvez également effectuer les opérations suivantes:
// The main entry point for the process
static void Main()
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new WinService1() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
Pour plus d'informations sur les services Windows, vous pouvez obtenir un exemple squelette ici .
Exemple de code présenté à l'aide d'une application console. espérons que cela aidera ..
class Program
{
private static CancellationTokenSource _cancellationTokenSource;
private static ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
private static Thread _serviceStartThread;
private static Thread _serviceStopThread;
private static int workcounter = 0;
static void Main(string[] args)
{
_cancellationTokenSource = new CancellationTokenSource();
_serviceStartThread = new Thread(DoWork);
_serviceStopThread = new Thread(ScheduledStop);
StartService();
StopService();
}
private static void StartService()
{
_serviceStartThread.Start();
}
private static void StopService()
{
_serviceStopThread.Start();
}
/// <summary>
/// Triggers a cancellation event for stopping the service in a timely fashion.
/// </summary>
private static void ScheduledStop()
{
while (!_shutdownEvent.WaitOne(0))
{
if (workcounter == 10)
{
_cancellationTokenSource.Cancel();
}
}
}
/// <summary>
/// Represents a long running Task with cancellation option
/// </summary>
private static void DoWork()
{
while (!_shutdownEvent.WaitOne(0))
{
if(!_cancellationTokenSource.Token.IsCancellationRequested)
{
workcounter += 1;
Console.Write(Environment.NewLine);
Console.Write("Running...counter: " + workcounter.ToString());
Thread.Sleep(1000);//Not needed, just for demo..
}
else
{
Console.Write(Environment.NewLine);
Console.Write("Recieved cancellation token,shutting down in 5 seconds.. counter: " + workcounter.ToString());
_shutdownEvent.Set();
Thread.Sleep(5000);//Not needed, just for demo..
}
}
}
}
Pourquoi ne créez-vous pas un nouveau projet dans votre solution du type Service Windows? Ceci configure toutes les structures que vous devez implémenter, y compris les gestionnaires pour les événements de démarrage/arrêt du service.