J'ai besoin d'écrire du code robuste en .NET pour permettre à un service Windows (serveur 2003) de se redémarrer. Quelle est la meilleure façon d'y parvenir? Existe-t-il une API .NET pour le faire?
J'ai besoin d'écrire du code robuste en .NET pour permettre à un service Windows (serveur 2003) de se redémarrer. Quelle est la meilleure façon d'y parvenir? Existe-t-il une API .NET pour le faire?
Réponses:
Configurez le service pour qu'il redémarre après une panne (double-cliquez sur le service dans le panneau de configuration et jetez un œil sur ces onglets - j'en oublie le nom). Ensuite, chaque fois que vous souhaitez que le service redémarre, appelez simplement Environment.Exit(1)
(ou tout retour différent de zéro) et le système d'exploitation le redémarrera pour vous.
Service.ExitCode = 1
puis exécuter Service.Stop()
en activant la case à cocher `` Activer les actions pour les arrêts avec erreurs '' sur l'écran des paramètres de récupération du service. Le faire de cette façon permet un arrêt correct et déclenche toujours le redémarrage.
Dim proc As New Process()
Dim psi As New ProcessStartInfo()
psi.CreateNoWindow = True
psi.FileName = "cmd.exe"
psi.Arguments = "/C net stop YOURSERVICENAMEHERE && net start YOURSERVICENAMEHERE"
psi.LoadUserProfile = False
psi.UseShellExecute = False
psi.WindowStyle = ProcessWindowStyle.Hidden
proc.StartInfo = psi
proc.Start()
Vous ne pouvez pas être sûr que le compte d'utilisateur sous lequel votre service s'exécute dispose même des autorisations pour arrêter et redémarrer le service.
Vous pouvez créer un processus qui est une invite de commande DOS qui redémarre vous-même:
Process process = new Process();
process.StartInfo.FileName = "cmd";
process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\"";
process.Start();
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\"";
Process.Start("CMD.exe", strCmdText);
où SERVICENAME
est le nom de votre service (les guillemets doubles inclus pour tenir compte des espaces dans le nom du service, peuvent être omis dans le cas contraire).
Propre, aucune configuration de redémarrage automatique nécessaire.
Cela dépendra de la raison pour laquelle vous souhaitez qu'il redémarre.
Si vous cherchez simplement un moyen de nettoyer périodiquement le service, vous pourriez avoir une minuterie en cours d'exécution dans le service qui provoque périodiquement une routine de purge.
Si vous recherchez un moyen de redémarrer en cas de panne, l'hôte de service lui-même peut fournir cette capacité lors de sa configuration.
Alors pourquoi avez-vous besoin de redémarrer le serveur? Qu'essayez-vous d'accomplir?
Je ne pense pas que vous puissiez dans un service autonome (lorsque vous appelez Restart, cela arrêtera le service, ce qui interrompra la commande Restart, et il ne redémarrera plus jamais). Si vous pouvez ajouter un deuxième .exe (une application de console qui utilise la classe ServiceManager), vous pouvez lancer le .exe autonome et lui faire redémarrer le service, puis quitter.
En y réfléchissant, vous pourriez probablement demander au service d'enregistrer une tâche planifiée (en utilisant la commande de ligne de commande «at», par exemple) pour démarrer le service et ensuite l'arrêter; cela fonctionnerait probablement.
Le problème avec le bombardement vers un fichier de commandes ou un EXE est qu'un service peut ou non disposer des autorisations nécessaires pour exécuter l'application externe.
Le moyen le plus propre de faire cela que j'ai trouvé est d'utiliser la méthode OnStop (), qui est le point d'entrée du Service Control Manager. Ensuite, tout votre code de nettoyage s'exécutera et vous n'aurez plus de sockets bloqués ni d'autres processus, en supposant que votre code d'arrêt fasse son travail.
Pour ce faire, vous devez définir un indicateur avant de terminer qui indique à la méthode OnStop de quitter avec un code d'erreur; alors le SCM sait que le service doit être redémarré. Sans cet indicateur, vous ne pourrez pas arrêter le service manuellement à partir du SCM. Cela suppose également que vous avez configuré le service pour qu'il redémarre en cas d'erreur.
Voici mon code d'arrêt:
...
bool ABORT;
protected override void OnStop()
{
Logger.log("Stopping service");
WorkThreadRun = false;
WorkThread.Join();
Logger.stop();
// if there was a problem, set an exit error code
// so the service manager will restart this
if(ABORT)Environment.Exit(1);
}
Si le service rencontre un problème et doit redémarrer, je lance un thread qui arrête le service du SCM. Cela permet au service de nettoyer après lui-même:
...
if(NeedToRestart)
{
ABORT = true;
new Thread(RestartThread).Start();
}
void RestartThread()
{
ServiceController sc = new ServiceController(ServiceName);
try
{
sc.Stop();
}
catch (Exception) { }
}
J'utiliserais le planificateur Windows pour planifier un redémarrage de votre service. Le problème est que vous ne pouvez pas redémarrer vous-même, mais vous pouvez vous arrêter. (Vous avez essentiellement scié la branche sur laquelle vous êtes assis ... si vous comprenez mon analogie) Vous avez besoin d'un processus séparé pour le faire pour vous. Le planificateur Windows est approprié. Planifiez une tâche unique pour redémarrer votre service (même à partir du service lui-même) à exécuter immédiatement.
Sinon, vous devrez créer un processus de "berger" qui le fera pour vous.
La première réponse à la question est la solution la plus simple: "Environment.Exit (1)" J'utilise ceci sur Windows Server 2008 R2 et cela fonctionne parfaitement. Le service s'arrête, le O / S attend 1 minute, puis le redémarre.
La meilleure approche peut être d'utiliser le service NT comme un wrapper pour votre application. Lorsque le service NT est démarré, votre application peut démarrer en mode "inactif" en attendant que la commande démarre (ou être configurée pour démarrer automatiquement).
Pensez à une voiture, lorsqu'elle a démarré, elle commence dans un état de ralenti, en attendant que votre commande avance ou recule. Cela permet également d'autres avantages, tels qu'une meilleure administration à distance, car vous pouvez choisir comment exposer votre application.
Juste en passant: et j'ai pensé ajouter quelques informations supplémentaires ...
vous pouvez également lancer une exception, cela fermera automatiquement le service Windows, et les options de redémarrage automatique se déclenchent. Le seul problème avec ceci est que si vous avez un environnement de développement sur votre PC, le JIT essaie de démarrer, et vous obtiendrez une invite indiquant le débogage O / N. dites non, puis il se fermera, puis redémarrera correctement. (sur un PC sans JIT, tout fonctionne). la raison pour laquelle je suis à la traîne, est que ce JIT est nouveau dans Win 7 (il fonctionnait bien avec XP, etc.) et que je tente de trouver un moyen de désactiver le JIT .... je peux essayer la méthode Environment.Exit mentionnée ici voir comment cela fonctionne aussi.
Kristian: Bristol, Royaume-Uni
Créez un fichier restart.bat comme celui-ci
@echo on
set once="C:\Program Files\MyService\once.bat"
set taskname=Restart_MyService
set service=MyService
echo rem %time% >%once%
echo net stop %service% >>%once%
echo net start %service% >>%once%
echo del %once% >>%once%
schtasks /create /ru "System" /tn %taskname% /tr '%once%' /sc onstart /F /V1 /Z
schtasks /run /tn %taskname%
Puis supprimez la tâche% taskname% lorsque votre% service% démarre
Créez un domaine d'application distinct pour héberger le code d'application. Lorsque le redémarrage est nécessaire, nous pourrions décharger et recharger le domaine d'application à la place du processus (service Windows). C'est ainsi que fonctionne le pool d'applications IIS, ils n'exécutent pas l'application asp.net directement, ils utilisent appdmain séparé.
Le moyen le plus simple est d'avoir un fichier batch avec:
net stop net start
et ajoutez le fichier au planificateur avec l'intervalle de temps souhaité
private static void RestartService(string serviceName)
{
using (var controller = new ServiceController(serviceName))
{
controller.Stop();
int counter = 0;
while (controller.Status != ServiceControllerStatus.Stopped)
{
Thread.Sleep(100);
controller.Refresh();
counter++;
if (counter > 1000)
{
throw new System.TimeoutException(string.Format("Could not stop service: {0}", Constants.Series6Service.WindowsServiceName));
}
}
controller.Start();
}
}