2008-10-21 144 views
118

我需要在.NET中編寫健壯的代碼以使Windows服務(服務器2003)能夠自行重啓。這樣做的最佳方式是什麼?是否有一些.NET API來做到這一點?Windows服務如何以編程方式重啓自身?

+6

「魯棒」是一個黃鼠狼字(https://stackoverflow.fogbugz.com/default.asp?W13086) - 你需要什麼特定的特徵? – 2008-10-21 00:40:04

回答

168

將服務設置爲在失敗後重新啓動(雙擊控制面板中的服務並查看這些選項卡 - 我忘記了它的名稱)。然後,只要您想要服務重新啓動,只需撥打Environment.Exit(1)(或任何非零返回),操作系統將爲您重啓。

+0

簡單的解決方案是最好的解決方案。只是這樣做來取代現有的「第二個過程來定期重啓第一個」設置。 – geofftnz 2010-03-20 02:22:01

+5

Fyi位置位於服務面板中,右鍵單擊相關服務並選擇屬性,然後選擇恢復選項卡。 – 2011-07-07 14:35:42

+13

我看到這是如何實現所需的行爲,但1的返回碼旨在告訴系統有錯誤。如果事實上沒有錯誤並且您只是想重新啓動您的服務,這不是不好的做法嗎? – mgttlinger 2013-05-29 13:47:52

3

我不認爲你可以在一個自包含的服務中(當你調用Restart時,它會停止服務,這會中斷Restart命令,並且它不會再次啓動)。如果您可以添加第二個.exe(一個使用ServiceManager類的控制檯應用程序),那麼您可以啓動獨立的.exe並讓它重新啓動服務,然後退出。

第二個想法是,您可能會讓該服務註冊一個計劃任務(例如,使用'at'命令的命令行)來啓動該服務,然後使其自行停止;這可能會起作用。

1

我不認爲它可以。當服務「停止」時,它將完全卸載。

好吧,好吧,總有一種方法,我想。例如,您可以創建一個分離的進程來停止該服務,然後重新啓動它,然後退出。

13

您無法確定您的服務在其下運行的用戶帳戶是否有權停止並重新啓動該服務。

+0

雖然在我面臨同樣的問題時出現+ 1問題,但在查看sc.exe時,事實證明,在調用OpenSCManager()時,它使用SERVICE_QUERY_CONFIG作爲dwDesiredAccess,然後使用SERVICE_START |調用OpenService() SERVICE_STOP打開一個特定的服務,它工作正常(訪問沒有問題)。不知道如何在.NET中完成這項工作。 – n0p 2015-11-10 09:20:37

0

更好的方法可能是使用NT服務作爲您的應用程序的包裝。當NT服務啓動時,您的應用程序可以以「空閒」模式啓動,等待命令啓動(或配置爲自動啓動)。

想想一輛汽車,當它開始時,它會在空閒狀態下開始,等待您的命令前進或後退。這也允許其他好處,例如更好的遠程管理,因爲您可以選擇如何公開您的應用程序。

5

這取決於你爲什麼要重新啓動自己。

如果您只是想找一種方法讓服務定期清理乾淨,那麼您可以在服務中定期運行一個計時器,以定期引起清除例程。

如果您正在尋找重啓失敗的方法 - 服務主機本身可以在安裝時提供該功能。

那麼,爲什麼你需要重新啓動服務器?你想達到什麼目的?

7

您可以創建一個過程,是重新開始自己一個DOS命令提示符:

Process process = new Process(); 
process.StartInfo.FileName = "cmd"; 
process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\""; 
process.Start(); 
2

我會使用Windows調度程序安排服務的重新啓動。問題是你不能重新啓動自己,但你可以阻止自己。 (你基本上已經擺脫了你所坐的分支......如果你得到我的比喻)你需要一個單獨的過程來爲你做。 Windows計劃程序是一個合適的。安排一次性任務以重新啓動您的服務(即使在服務內部)立即執行。

否則,你將不得不創建一個「牧羊人」的過程,爲你做。

-2

最簡單的方法是有一個批處理文件:

淨停止 網絡啓動

和文件,所需時間間隔

-3
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(); 
     } 
    } 
1

的第一個反應添加到調度問題是最簡單的解決方案:「Environment.Exit(1)」我在Windows Server 2008 R2上使用它,它完美地工作。服務自行停止,O/S等待1分鐘,然後重新啓動。

22
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() 
0

剛好路過:以爲我會添加一些額外的信息...

你也可以拋出一個異常,這將自動關閉窗口服務,並自動重新啓動選項只是踢。唯一的問題是,如果你的電腦上有開發環境,那麼JIT會嘗試啓動,你會得到一個提示說調試Y/N。說不,然後它會關閉,然後重新正常啓動。 (在沒有JIT的PC上,它只是所有的作品)。 即時通訊的原因是,這是JIT是新的贏得7(它曾與XP等工作正常),即時通訊試圖找到一種方法禁用JIT ....我可以嘗試這裏提到的Environment.Exit方法看到這也是如此。

克里斯蒂安:英國布裏斯托爾

8
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\""; 
Process.Start("CMD.exe", strCmdText); 

其中SERVICENAME是您的服務的名稱(包括雙引號,以考慮該服務的名稱空間,可省略否則)。

清潔,不需要自動重新啓動配置。

0

像這樣創建

@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% 

一個restart.bat文件然後刪除任務%在您%的服務啓動%

1

創建一個單獨的AppDomain來託管應用程序代碼TASKNAME%。當需要重新啓動時,我們可以卸載並重新加載appdomain,而不是進程(Windows服務)。這是IIS應用程序池的工作方式,他們不直接運行asp.net應用程序,他們使用單獨的appdmain。

2

脫殼到批處理文件或EXE的問題是,服務可能具有或不具有運行外部應用程序所需的權限。

我發現的最簡單的方法是使用OnStop()方法,它是服務控制管理器的入口點。然後,所有清理代碼都會運行,假設您的停止代碼正在完成其工作,您將不會有任何掛起的套接字或其他進程。

要做到這一點,您需要在終止之前設置一個標誌,告訴OnStop方法以錯誤代碼退出;那麼SCM知道該服務需要重新啓動。沒有此標誌,您將無法從SCM手動停止該服務。這也假定你已經設置了服務來重新啓動一個錯誤。

這裏是我的停止代碼:

... 

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); 
} 

如果該服務運行到一個問題,需要重新啓動,我啓動從SCM停止服務的線程。這可以讓服務自行清理:

... 

if(NeedToRestart) 
{ 
    ABORT = true; 
    new Thread(RestartThread).Start(); 
} 

void RestartThread() 
{ 
    ServiceController sc = new ServiceController(ServiceName); 
    try 
    { 
     sc.Stop(); 
    } 
    catch (Exception) { } 
} 
0

nssm非常棒。它會爲你做這一切

相關問題