2011-01-13 20 views
62

是否可以在Visual Studio中調試Windows服務?如何在Visual Studio中調試Windows服務?

我用這樣的代碼

System.Diagnostics.Debugger.Break(); 

,但它給一些代碼錯誤,如

I got two event error: eventID 4096 VsJITDebugger and "The service did not respond to the start or control request in a timely fashion. "

回答

54

你也可以試試這個。

  1. 創建您的Windows服務並安裝並啓動...。也就是說,Windows服務必須在您的系統中運行。
  2. 當你的服務正在運行,進入調試菜單,點擊安裝過程(或處理舊的Visual Studio)
  3. 找到你正在運行的服務,並確保對所有用戶顯示過程在所有會話中顯示進程被選中,如果沒有,則選擇它。

enter image description here

  • 點擊附加按鈕
  • 點擊OK
  • 點擊關閉
  • 設置一個破發點,以你的希望位置並等待執行。只要您的代碼達到該點,它就會自動進行調試。
  • 記住,把你的斷點到達的地方,如果是在onStart(),然後停止和啓動服務再次
  • (很多谷歌搜索後,我發現這在「如何在Visual Studio中調試Windows服務「)。

    20

    你應該分離出所有的代碼,將東西從服務項目到一個單獨的項目,然後創建一個可以正常運行和調試的測試應用程序。

    服務項目將只是實現服務部分所需的shell。

    +0

    OOW !!按Ctrl + C然後Ctrl + V,我的意思是新項目。雅只有我在做。是不是可以附加任何進程調試或任何其他選項,而不是單獨的項目。 – PawanS 2011-01-13 10:15:05

    +1

    當然,這是可能的,但如果您在開發過程中取出服務部分,開發Windows服務會更容易。 – 2011-01-13 10:17:27

    +0

    嗯......這是很好的方式,但它只是雙打工作。我想其他任何方式都會存在。 – PawanS 2011-01-13 10:26:38

    13

    要麼由Lasse V. Karlsen建議,要麼在您的服務中設置一個等待調試器附加的循環。最簡單的是

    while (!Debugger.IsAttached) 
    { 
        Thread.Sleep(1000); 
    } 
    
    ... continue with code 
    

    這樣,你可以啓動該服務,並在Visual Studio中選擇「附加到進程...」,並連接到您的服務,然後將恢復正常exution。

    +0

    我應該在哪裏放置上面的代碼......並且在附加過程中,我得到的服務名爲disable – PawanS 2011-01-13 10:24:49

    2

    您可以製作控制檯應用程序。我用這個main功能:

    static void Main(string[] args) 
        { 
         ImportFileService ws = new ImportFileService(); 
         ws.OnStart(args); 
         while (true) 
         { 
          ConsoleKeyInfo key = System.Console.ReadKey(); 
          if (key.Key == ConsoleKey.Escape) 
           break; 
         } 
         ws.OnStop(); 
        } 
    

    ImportFileService類是完全一樣在我的Windows服務的應用程序,除了inheritant(ServiceBase)。

    1

    不幸的是,如果您嘗試在Windows服務操作剛開始時調試某些內容,則」正在附加「到正在運行的進程將不起作用。我試過的OnStart procecdure內使用Debugger.Break(),但有64位,10 VS編譯的應用程序,break命令只是拋出這樣的錯誤:

    System error 1067 has occurred. 
    

    在這一點上,你需要什麼do在您的註冊表中爲您的可執行文件設置了「Image File Execution」選項。它需要5分鐘的時間來安裝,並且工作得很好。下面是MS的鏈接,其中的細節是:

    http://msdn.microsoft.com/en-us/library/a329t4ed(v=vs.100).aspx

    2

    您也可以嘗試System.Diagnostics.Debugger.Launch()方法。它有助於將調試指針指向指定的位置,然後您可以調試代碼。 installutil projectservice.exe

    然後開始從控制面板爲您服務 - -

    這一步之前,請使用Visual Studio命令提示符下的命令行安裝您service.exe>管理工具 - >計算機管理 - >服務和應用程序 - >服務 - >您的服務名稱

    4

    鑑於ServiceBase.OnStartprotected知名度,我走下反射途徑來實現調試。

    private static void Main(string[] args) 
    { 
        var serviceBases = new ServiceBase[] {new Service() /* ... */ }; 
    
    #if DEBUG 
        if (Environment.UserInteractive) 
        { 
         const BindingFlags bindingFlags = 
          BindingFlags.Instance | BindingFlags.NonPublic; 
    
         foreach (var serviceBase in serviceBases) 
         { 
          var serviceType = serviceBase.GetType(); 
          var methodInfo = serviceType.GetMethod("OnStart", bindingFlags); 
    
          new Thread(service => methodInfo.Invoke(service, new object[] {args})).Start(serviceBase); 
         } 
    
         return; 
        } 
    #endif 
    
        ServiceBase.Run(serviceBases); 
    } 
    

    注意Thread是,默認情況下,一個前臺線程。 returnMain當人造服務線程正在運行時不會終止進程。

    2

    我只是將此代碼添加到我的服務類,所以我可以間接調用OnStart,類似於OnStop。

    public void MyOnStart(string[] args) 
        { 
         OnStart(args); 
        } 
    
    96

    使用的服務OnStart方法如下代碼:

    System.Diagnostics.Debugger.Launch(); 
    

    選擇從彈出消息Visual Studio的選項。

    注意:要在調試模式下使用它,可以使用#if DEBUG編譯器指令,如下所示。這將防止生產服務器上的發佈模式中的意外或調試。

    #if DEBUG 
        System.Diagnostics.Debugger.Launch(); 
    #endif 
    
    2

    我使用的Visual Studio項目調試/控制檯參數>啓動選項>命令行參數:

    public static class Program 
    { 
        [STAThread] 
        public static void Main(string[] args) 
        { 
         var runMode = args.Contains(@"/Console") 
          ? WindowsService.RunMode.Console 
          : WindowsService.RunMode.WindowsService; 
         new WinodwsService().Run(runMode); 
        } 
    } 
    
    
    public class WindowsService : ServiceBase 
    { 
        public enum RunMode 
        { 
         Console, 
         WindowsService 
        } 
    
        public void Run(RunMode runMode) 
        { 
         if (runMode.Equals(RunMode.Console)) 
         { 
          this.StartService(); 
          Console.WriteLine("Press <ENTER> to stop service..."); 
          Console.ReadLine(); 
    
          this.StopService(); 
          Console.WriteLine("Press <ENTER> to exit."); 
          Console.ReadLine(); 
         } 
         else if (runMode.Equals(RunMode.WindowsService)) 
         { 
          ServiceBase.Run(new[] { this }); 
         } 
        } 
    
        protected override void OnStart(string[] args) 
        { 
         StartService(args); 
        } 
    
        protected override void OnStop() 
        { 
         StopService(); 
        } 
    
        /// <summary> 
        /// Logic to Start Service 
        /// Public accessibility for running as a console application in Visual Studio debugging experience 
        /// </summary> 
        public virtual void StartService(params string[] args){ ... } 
    
        /// <summary> 
        /// Logic to Stop Service 
        /// Public accessibility for running as a console application in Visual Studio debugging experience 
        /// </summary> 
        public virtual void StopService() {....} 
    } 
    
    0

    OnStart方法做以下。

    protected override void OnStart(string[] args) 
         { 
          try 
          { 
           RequestAdditionalTime(600000); 
           System.Diagnostics.Debugger.Launch(); // put brake point here. 
           ............. your code 
          } 
          catch (Exception ex) 
          { 
           ......... your exception code 
          } 
         } 
    

    然後運行命令提示符以管理員身份,並把下面

    c:\> sc create test-xyzService binPath= <ProjectPath>\bin\debug\service.exe type= own start= demand 
    

    以上的生產線將在服務列表中創建測試xyzService

    啓動服務,這將提示您隨員登場VS與否。

    c:\> sc start text-xyzService 
    

    停止服務

    c:\> sc stop test-xyzService 
    

    刪除或卸載

    c:\> sc delete text-xyzService 
    
    1

    人都有每個人嘗試過的VS的自己生成後事件命令行

    嘗試在添加此生成後

    @echo off 
    sc query "ServiceName" > nul 
    if errorlevel 1060 goto install 
    goto stop 
    
    :delete 
    echo delete 
    sc delete "ServiceName" > nul 
    echo %errorlevel% 
    goto install 
    
    :install 
    echo install 
    sc create "ServiceName" displayname= "Service Display Name" binpath= "$(TargetPath)" start= auto > nul 
    echo %errorlevel% 
    goto start 
    
    :start 
    echo start 
    sc start "ServiceName" > nul 
    echo %errorlevel% 
    goto end 
    
    :stop 
    echo stop 
    sc stop "ServiceName" > nul 
    echo %errorlevel% 
    goto delete 
    
    :end 
    

    如果與像Error 1 The command "@echo off sc query "ServiceName" > nul等,CTRL-C然後CTRL-V的錯誤信息到記事本中,並期待消息的最後一句消息生成錯誤。它可以是exited with code x。在這裏查找一些常見錯誤的代碼,看看如何解決它。

    1072 -- marked for deletion --> close all apps that maybe using the service including services.msc and windows event log. 
    1058 -- cant be started because disabled or has no enabled associated devices --> just delete it. 
    1060 -- doesnt exist --> just delete it. 
    1062 -- has not been started --> just delete it. 
    1053 -- didnt response to start or control --> see event log (if logged to event log). it maybe the service itself throw an exception 
    1056 -- service is already running --> stop the service then delete. 
    

    更多的錯誤代碼here

    ,如果有消息生成錯誤這樣

    Error 11 Could not copy "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". Exceeded retry count of 10. Failed. ServiceName 
    Error 12 Unable to copy file "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". The process cannot access the file 'bin\Debug\ServiceName.exe' because it is being used by another process. ServiceName 
    

    打開CMD,然後嘗試用taskkill /fi "services eq ServiceName" /f

    先殺死它,如果一切都很好,F5應該足以對其進行調試。

    1

    Microsoft文章介紹瞭如何調試Windows服務here以及如果通過附加到進程進行調試,任何人都可能會錯過的部分。

    以下是我的工作代碼。我遵循微軟建議的方法。

    添加該代碼Program.cs中

    static void Main(string[] args) 
         { 
          // if block will execute when launched through Visual studio 
          if (Environment.UserInteractive) 
          { 
           ServiceMonitor serviceRequest = new ServiceMonitor(); 
           serviceRequest.TestOnStartAndOnStop(args); 
          } 
          else // This block will execute when code is compiled as windows application 
          { 
           ServiceBase[] ServicesToRun; 
           ServicesToRun = new ServiceBase[] 
           { 
            new ServiceMonitor() 
           }; 
           ServiceBase.Run(ServicesToRun); 
          } 
         } 
    

    這個代碼添加到ServiceMonitor類。

    internal void TestOnStartAndOnStop(string[] args) 
         { 
          this.OnStart(args); 
          Console.ReadLine(); 
          this.OnStop(); 
         } 
    

    現在去項目屬性,選擇選項卡「應用程序」,當與調試已完成選擇輸出類型爲「控制檯應用程序」調試時或「Windows應用程序」,重新編譯和安裝服務。 enter image description here

    0

    發現此線程,但我認爲一個清晰和簡單的答案缺失。我不想將調試器附加到進程中,但我仍然無法調用服務OnStartOnStop方法。我也不想將它作爲控制檯應用程序運行,以便我可以將信息從Nlog記錄到控制檯。通過改變項目Output typeConsole Application

    https://coding.abel.nu/2012/05/debugging-a-windows-service-project/

    https://stackoverflow.com/a/10838170/3850405

    開始:

    發現這些輝煌的指南,做到這一點。

    enter image description here

    更改您的Program.cs看起來像這樣:

    static class Program 
    { 
        /// <summary> 
        /// The main entry point for the application. 
        /// </summary> 
        static void Main() 
        { 
    
         // Startup as service. 
         ServiceBase[] ServicesToRun; 
         ServicesToRun = new ServiceBase[] 
         { 
           new Service1() 
         }; 
    
         if (Environment.UserInteractive) 
         { 
          RunInteractive(ServicesToRun); 
         } 
         else 
         { 
          ServiceBase.Run(ServicesToRun); 
         } 
    
        } 
    } 
    

    然後添加下面的方法,以允許在交互模式下運行的服務。

    static void RunInteractive(ServiceBase[] servicesToRun) 
    { 
        Console.WriteLine("Services running in interactive mode."); 
        Console.WriteLine(); 
    
        MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart", 
         BindingFlags.Instance | BindingFlags.NonPublic); 
        foreach (ServiceBase service in servicesToRun) 
        { 
         Console.Write("Starting {0}...", service.ServiceName); 
         onStartMethod.Invoke(service, new object[] { new string[] { } }); 
         Console.Write("Started"); 
        } 
    
        Console.WriteLine(); 
        Console.WriteLine(); 
        Console.WriteLine(
         "Press any key to stop the services and end the process..."); 
        Console.ReadKey(); 
        Console.WriteLine(); 
    
        MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop", 
         BindingFlags.Instance | BindingFlags.NonPublic); 
        foreach (ServiceBase service in servicesToRun) 
        { 
         Console.Write("Stopping {0}...", service.ServiceName); 
         onStopMethod.Invoke(service, null); 
         Console.WriteLine("Stopped"); 
        } 
    
        Console.WriteLine("All services stopped."); 
        // Keep the console alive for a second to allow the user to see the message. 
        Thread.Sleep(1000); 
    }