Devo scrivere un codice affidabile in .NET per abilitare un servizio Windows (server 2003) a riavviarsi. Qual è il modo migliore per farlo? C'è qualche API .NET per farlo?
Devo scrivere un codice affidabile in .NET per abilitare un servizio Windows (server 2003) a riavviarsi. Qual è il modo migliore per farlo? C'è qualche API .NET per farlo?
Risposte:
Imposta il riavvio del servizio dopo un errore (fai doppio clic sul servizio nel pannello di controllo e dai un'occhiata in quelle schede - Ho dimenticato il nome). Quindi, ogni volta che vuoi riavviare il servizio, chiama Environment.Exit(1)
(o qualsiasi ritorno diverso da zero) e il sistema operativo lo riavvierà per te.
Service.ExitCode = 1
e quindi eseguire Service.Stop()
insieme con la casella di controllo "Abilita azioni per fermate con errori" nella schermata delle impostazioni di ripristino del servizio. In questo modo consente un arresto corretto e innesca ancora il riavvio.
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()
Non puoi essere sicuro che l'account utente su cui è in esecuzione il tuo servizio disponga anche delle autorizzazioni per arrestare e riavviare il servizio.
È possibile creare un processo che è un prompt dei comandi DOS che si riavvia:
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);
dov'è SERVICENAME
il nome del tuo servizio (le doppie virgolette incluse per tenere conto degli spazi nel nome del servizio, possono essere omesse in altro modo).
Pulito, nessuna configurazione di riavvio automatico necessaria.
Dipenderebbe dal motivo per cui si desidera che si riavvii da solo.
Se stai solo cercando un modo per fare in modo che il servizio si pulisca periodicamente, allora potresti avere un timer in esecuzione nel servizio che provoca periodicamente una routine di spurgo.
Se stai cercando un modo per riavviare in caso di errore, l'host del servizio stesso può fornire tale capacità durante l'installazione.
Quindi perché è necessario riavviare il server? Cosa stai cercando di ottenere?
Non penso che tu possa farlo in un servizio autonomo (quando chiami Riavvia, il servizio verrà interrotto, interrompendo il comando Riavvia e non verrà mai riavviato). Se puoi aggiungere un secondo .exe (un'app Console che utilizza la classe ServiceManager), puoi dare il via al file .exe autonomo e farlo riavviare il servizio, quindi uscire.
Ripensandoci, è possibile che il servizio registri un'attività pianificata (ad esempio utilizzando il comando "at" della riga di comando) per avviare il servizio e farlo arrestare automaticamente; probabilmente funzionerebbe.
Il problema con lo sbandamento verso un file batch o EXE è che un servizio può o meno disporre delle autorizzazioni necessarie per eseguire l'app esterna.
Il modo più pulito per fare ciò che ho trovato è utilizzare il metodo OnStop (), che è il punto di ingresso per Gestione controllo servizi. Quindi verrà eseguito tutto il codice di pulizia e non avrai socket sospesi o altri processi, supponendo che il codice di arresto stia facendo il suo lavoro.
Per fare ciò è necessario impostare un flag prima di terminare che indica al metodo OnStop di uscire con un codice di errore; quindi SCM sa che il servizio deve essere riavviato. Senza questo flag non sarà possibile interrompere manualmente il servizio da SCM. Ciò presuppone inoltre che il servizio sia stato impostato per il riavvio in caso di errore.
Ecco il mio codice di stop:
...
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);
}
Se il servizio presenta un problema e deve essere riavviato, avvio un thread che interrompe il servizio da SCM. Ciò consente al servizio di ripulire dopo se stesso:
...
if(NeedToRestart)
{
ABORT = true;
new Thread(RestartThread).Start();
}
void RestartThread()
{
ServiceController sc = new ServiceController(ServiceName);
try
{
sc.Stop();
}
catch (Exception) { }
}
Vorrei utilizzare l'Utilità di pianificazione di Windows per pianificare un riavvio del servizio. Il problema è che non puoi riavviarti, ma puoi fermarti. (In sostanza hai segato il ramo su cui sei seduto ... se ottieni la mia analogia) Hai bisogno di un processo separato per farlo per te. L'utilità di pianificazione di Windows è appropriata. Pianifica un'attività una tantum per riavviare il servizio (anche dall'interno del servizio stesso) per l'esecuzione immediata.
Altrimenti, dovrai creare un processo di "pastorizia" che lo faccia per te.
La prima risposta alla domanda è la soluzione più semplice: "Environment.Exit (1)" Sto usando questo su Windows Server 2008 R2 e funziona perfettamente. Il servizio si arresta automaticamente, l'O / S attende 1 minuto, quindi lo riavvia.
L'approccio migliore potrebbe essere quello di utilizzare il servizio NT come wrapper per l'applicazione. All'avvio del servizio NT, l'applicazione può avviarsi in modalità "inattiva" in attesa dell'avvio del comando (o essere configurata per l'avvio automatico).
Pensa a un'auto, quando è avviata inizia in uno stato inattivo, in attesa che il tuo comando vada avanti o indietro. Ciò consente anche altri vantaggi, come una migliore amministrazione remota in quanto è possibile scegliere come esporre l'applicazione.
Solo passando: e ho pensato di aggiungere alcune informazioni extra ...
puoi anche lanciare un'eccezione, questo chiuderà automaticamente il servizio di Windows e le opzioni di riavvio automatico si avvieranno. L'unico problema è che se hai un ambiente di sviluppo sul tuo PC, allora la JIT prova a dare il via, e riceverai un prompt che dice debug S / N. dire di no e poi si chiuderà, quindi ricominciare correttamente. (su un PC senza JIT funziona solo tutto). il motivo per cui sto trollando, è che JIT è nuovo su Win 7 (funzionava bene con XP ecc.) e sto cercando di trovare un modo per disabilitare JIT .... potrei provare il metodo Environment.Exit menzionato qui, vedere come anche quello funziona.
Kristian: Bristol, Regno Unito
Crea un file restart.bat come questo
@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%
Quindi eliminare l'attività% taskname% all'avvio di% service%
Crea un appdomain separato per ospitare il codice dell'applicazione. Quando è necessario il riavvio, è possibile scaricare e ricaricare l'appdomain anziché il processo (servizio Windows). Ecco come funziona il pool di app IIS, non eseguono direttamente l'app asp.net, usano appdmain separato.
Il modo più semplice è avere un file batch con:
net stop net start
e aggiungi il file allo scheduler con l'intervallo di tempo desiderato
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();
}
}