调试 Windows 服务的更简单方法

Posted

技术标签:

【中文标题】调试 Windows 服务的更简单方法【英文标题】:Easier way to debug a Windows service 【发布时间】:2010-09-12 15:53:44 【问题描述】:

有没有比通过 Windows 服务控制管理器启动服务然后将调试器附加到线程更简单的方法来单步执行代码?这有点麻烦,我想知道是否有更直接的方法。

【问题讨论】:

我创建了这张用户语音票。考虑为它投票:visualstudio.uservoice.com/forums/121579-visual-studio-ide/… 【参考方案1】:

如果我想快速调试服务,我只需在其中输入Debugger.Break()。当到达那条线时,它会让我回到 VS。完成后不要忘记删除该行。

更新:作为#if DEBUG pragmas 的替代方法,您还可以使用Conditional("DEBUG_SERVICE") 属性。

[Conditional("DEBUG_SERVICE")]
private static void DebugMode()

    Debugger.Break();

在您的OnStart 上,只需调用此方法:

public override void OnStart()

     DebugMode();
     /* ... do the rest */

在那里,代码只会在调试构建期间启用。当您使用它时,为服务调试创建一个单独的构建配置可能会很有用。

【讨论】:

或者你可以使用 Debugger.Launch() 你必须包含一个用于 Systems.Diagnostics 命名空间的 using 语句。 您的博客文章运行良好,节省了我的时间:) 但是 Debugger.Break() 对我不起作用。 .Net 似乎出于一些与优化相关的原因跳过了 DebugMode 函数。 Debugger.Launch() 对我有用,而 Debugger.Break() 不起作用。 (进程以代码 255 退出。) 你们是如何让它工作的?什么都没发生。我试过 Break() 和 Launch()。 @4thSpace: 1. 为你的服务创建一个安装程序,这样你就可以安装你的服务了。 2. 添加一行 Debugger.Launch();在 Main() 的开头。 3. 在调试模式下构建您的代码。 4. 用 debug-dll 覆盖已安装的 dll。 5. 从 Windows 服务面板启动服务。现在出现一个弹出窗口,要求您附加到调试器。这种方式对我有用。希望你也一样。【参考方案2】:

我也认为有一个单独的“版本”用于正常执行和作为服务是要走的路,但是否真的需要为此目的专用一个单独的命令行开关?

你就不能这样做吗:

public static int Main(string[] args)

  if (!Environment.UserInteractive)
  
    // Startup as service.
  
  else
  
    // Startup as application
  

这将有“好处”,您可以通过双击启动您的应用程序(好的,如果您真的需要的话)并且您可以在 Visual Studio 中点击 F5 (无需修改项目设置以包含 /console 选项)。

从技术上讲,Environment.UserInteractive 检查是否为当前窗口站设置了WSF_VISIBLE 标志,但除了作为(非交互式)服务运行之外,是否还有其他原因会返回false ?

【讨论】:

太棒了!我之前使用“if #debug”方法在调试时作为应用程序启动,否则作为服务启动。如果你想调试它,这会导致应用程序无法作为服务运行,但你的解决方案解决了这个问题,并让它在服务/应用程序和发布/调试的所有四种组合中都可以运行。 如果您不希望程序在双击时运行(用户可能会感到困惑并运行多个实例等),那么您可以使用System.Diagnostics.Debugger.IsAttached 而不是Environment.UserInteractive。跨度> 但是除了作为(非交互式)服务运行之外,还有其他原因会返回 false 吗? 我可以想到一个:不附加到控制台。 我在这种情况下使用命令行参数。 --install 安装服务, --uninstall 卸载服务, --interactive 将服务作为应用程序运行。我将 --interactive 添加到项目选项(调试>命令参数)。所以我可以很容易地从 VS 调试。双击不会创建不需要的运行实例,因为 --interactive 是必需的。只是我的 2 美分。 @EmirAkaydın 是的,实际上我也有命令行参数作为“备份”。但是,我实际上想要在双击时有一个“交互式”实例,而不是关于无法以这种方式启动服务的错误消息。我猜不同的目标;-)【参考方案3】:

几周前,当我建立一个新的服务项目时,我发现了这篇文章。虽然有很多很好的建议,但我仍然没有找到我想要的解决方案:无需对服务类进行任何修改即可调用服务类的 OnStartOnStop 方法。

我想出的解决方案使用 Environment.Interactive 选择运行模式,正如本文其他答案所建议的那样。

static void Main()

    ServiceBase[] servicesToRun;
    servicesToRun = new ServiceBase[] 
    
        new MyService()
    ;
    if (Environment.UserInteractive)
    
        RunInteractive(servicesToRun);
    
    else
    
        ServiceBase.Run(servicesToRun);
    

RunInteractive 助手使用反射来调用受保护的 OnStartOnStop 方法:

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

这是所需的所有代码,但我还写了walkthrough 并附有解释。

【讨论】:

确实很棒的解决方案。正如大卫建议的那样,我为 ServiceBase[] 创建了一个简单的扩展,它只允许在一行代码中运行服务:pastebin.com/F0fhhG2R +1 我以前的一位同事创建了一个“EasyRunService”基类(它继承了 ServiceProcess),它做的事情几乎相同,但不需要反射(因为 OnStart 现在在基类中)。它确实使调试 Windows 服务变得轻而易举。 @Chazt3n 确保您的项目输出类型设置为“控制台应用程序”。至于服务安装,不管选择哪种输出类型,行为都是一样的。 仍然是一个很好的解决方案!我唯一要添加的(如walk through 所示)是确保在尝试编译和运行之前进入项目的属性并将输出类型更改为Console Application。在Project Properties -> Application -> Output type -> Console Application 找到它。此外,为了让这对我正常工作,我最终不得不使用start 命令运行应用程序。例如:C:\"my app name.exe" -service 对我不起作用。相反,我使用了C:\start /wait "" "my app name.exe" -service +1 这是一个很好的解决方案(Windows 服务 - .NET 4.0)。根据上面的评论,向@Funbit 大喊他对 ServiceBase 的扩展方法!【参考方案4】:

有时分析在服务启动期间发生的情况很重要。附加到进程在这里没有帮助,因为在服务启动时附加调试器的速度不够快启动。

简短的回答是,我使用以下 4 行代码 来执行此操作:

#if DEBUG
    base.RequestAdditionalTime(600000); // 600*1000ms = 10 minutes timeout
    Debugger.Launch(); // launch and attach debugger
#endif

这些被插入到服务的OnStart方法中,如下:

protected override void OnStart(string[] args)

    #if DEBUG
       base.RequestAdditionalTime(600000); // 10 minutes timeout for startup
       Debugger.Launch(); // launch and attach debugger
    #endif
    MyInitOnstart(); // my individual initialization code for the service
    // allow the base class to perform any work it needs to do
    base.OnStart(args);

对于那些以前没有做过的人,我在下面提供了详细的提示,因为你很容易被卡住。以下提示适用于 Windows 7x64Visual Studio 2010 Team Edition,但也应适用于其他环境。


重要提示:“手动”模式部署服务(使用 VS 命令提示符下的 InstallUtil 实用程序或运行您准备好的服务安装程序项目) . 在启动服务之前打开 Visual Studio 并加载包含服务源代码的解决方案 - 根据需要在 Visual Studio 中设置额外的断点 - 然后通过服务控制面板启动服务。

由于Debugger.Launch 代码,这将导致对话框“Servicename.exe 中出现未处理的 Microsoft .NET Framework 异常。”出现。点击是的,调试Servicename.exe如截图所示:

之后,尤其是在 Windows 7 UAC 中,可能会提示您输入管理员凭据。输入它们并继续Yes

之后,众所周知的 Visual Studio 即时调试器窗口 会出现。它会询问您是否要使用 delected 调试器进行调试。 在您点击之前,选择您不想打开新实例(第二个选项) - 新实例没有帮助在这里,因为不会显示源代码。因此,您选择之前打开的 Visual Studio 实例:

点击Yes后,一段时间后,Visual Studio 将在Debugger.Launch 语句所在的行显示黄色箭头,您就可以进行调试了您的代码(方法MyInitOnStart,其中包含您的初始化)。

按下 F5 会立即继续执行,直到到达您准备的下一个断点。

提示:要保持服务运行,请选择Debug -> Detach all。这允许您在服务正确启动并完成调试启动代码后运行与服务通信的客户端。如果按Shift+F5(停止调试),这将终止服务。而不是这样做,您应该使用服务控制面板来停止它。

注意

如果你构建一个Release,那么调试代码会被自动移除并且服务正常运行。

我正在使用 Debugger.Launch(),它启动并附加调试器。我也测试了 Debugger.Break(),它不起作用,因为在启动服务时还没有附加调试器(导致 “错误 1067 :进程意外终止。”)。

RequestAdditionalTime 设置更长的服务启动超时(它不是延迟代码本身,而是将立即继续Debugger.Launch 语句)。否则,启动服务的默认超时时间太短,如果您没有从调试器中足够快地调用base.Onstart(args),则启动服务会失败。实际上,10 分钟的超时可避免您在调试器启动后立即看到消息“服务没有响应...”

一旦你习惯了,这个方法就非常简单,因为它只需要你在现有的服务代码中添加4行,让你快速获得控制和调试。

【讨论】:

出于好奇,您知道用户与 Debugger.Launch() 用户提示的交互是否超时? 如上所述,如果base.RequestAdditionalTime(600000) 在该时间段内未调用base.OnStart(args),则base.RequestAdditionalTime(600000) 将阻止服务控制终止服务10 分钟)。除此之外,我记得如果您在一段时间后不输入管理员凭据,UAC 也会中止(我不知道确切的秒数,但我认为您必须在一分钟内输入,否则 UAC 中止) ,这将终止调试会话。 我发现这是调试 CustomCommand 消息的最佳方法。 +1。【参考方案5】:

我通常做的是将服务的逻辑封装在一个单独的类中,并从一个“跑步者”类开始。这个运行器类可以是实际的服务或只是一个控制台应用程序。所以你的解决方案有(至少)3个项目:

/ConsoleRunner
   /....
/ServiceRunner
   /....
/ApplicationLogic
   /....

【讨论】:

我曾经也使用过这种方法,但我认为将这种方法和上面的答案结合起来很有效。【参考方案6】:

这个YouTube video by Fabio Scopel 解释了如何很好地调试 Windows 服务...实际操作方法从视频中的 4:45 开始...

这是视频中解释的代码...在您的 Program.cs 文件中,为“调试”部分添加内容...

namespace YourNamespace

    static class Program
    
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        
#if DEBUG
            Service1 myService = new Service1();
            myService.OnDebug();
            System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            
                new Service1()
            ;
            ServiceBase.Run(ServicesToRun);
#endif

        
    

在您的 Service1.cs 文件中,添加 OnDebug() 方法...

    public Service1()
    
        InitializeComponent();
    

    public void OnDebug()
    
        OnStart(null);
    

    protected override void OnStart(string[] args)
    
        // your code to do something
    

    protected override void OnStop()
    
    

它是如何工作的

基本上,您必须创建一个调用OnStart(string[] args)public void OnDebug(),因为它受到保护并且无法在外部访问。 void Main() 程序与#if 预处理器和#DEBUG 一起添加。

Visual Studio 定义DEBUG 如果项目在调试模式下编译。这将允许调试部分(如下)在条件为真时执行

Service1 myService = new Service1();
myService.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);

它会像控制台应用程序一样运行,一旦一切正常,您可以更改模式Release,常规的else 部分将触发逻辑

【讨论】:

我一直在寻找这个答案,不知道为什么它的排名这么低。解释代码以帮助其他人或可能更多的 cmets ;)【参考方案7】:

更新

这种方法是迄今为止最简单的:

http://www.codeproject.com/KB/dotnet/DebugWinServices.aspx

我将我的原始答案留在下面以供后代使用。


我的服务往往有一个封装了 Timer 的类,因为我希望该服务定期检查是否有任何工作要做。

我们新建类并在服务启动期间调用 StartEventLoop()。 (这个类也可以很容易地从控制台应用程序中使用。)

这种设计的好处是,您设置 Timer 时使用的参数可用于在服务实际开始工作之前有一个延迟,以便您有时间手动附加调试器。

附言How to attach the debugger manually 到正在运行的进程...?

using System;
using System.Threading;
using System.Configuration;    

public class ServiceEventHandler

    Timer _timer;
    public ServiceEventHandler()
    
        // get configuration etc.
        _timer = new Timer(
            new TimerCallback(EventTimerCallback)
            , null
            , Timeout.Infinite
            , Timeout.Infinite);
    

    private void EventTimerCallback(object state)
    
        // do something
    

    public void StartEventLoop()
    
        // wait a minute, then run every 30 minutes
        _timer.Change(TimeSpan.Parse("00:01:00"), TimeSpan.Parse("00:30:00");
    

我也曾经做过以下事情(在之前的答案中已经提到,但使用条件编译器 [#if] 标志来帮助避免它在发布版本中触发)。

我不再这样做了,因为有时我们会忘记在 Release 中构建并在客户端演示上运行的应用程序中出现调试器中断(尴尬!)。

#if DEBUG
if (!System.Diagnostics.Debugger.IsAttached)

    System.Diagnostics.Debugger.Break();

#endif

【讨论】:

// do something 需要超过 30 分钟才能完成时会发生什么?【参考方案8】:
static void Main()

#if DEBUG
                // Run as interactive exe in debug mode to allow easy
                // debugging.

                var service = new MyService();
                service.OnStart(null);

                // Sleep the main thread indefinitely while the service code
                // runs in .OnStart

                Thread.Sleep(Timeout.Infinite);
#else
                // Run normally as service in release mode.

                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[] new MyService() ;
                ServiceBase.Run(ServicesToRun);
#endif

【讨论】:

[抱歉没有解释代码 - 降价问题] 应该在调试版本中从 MS Visual Studio (F5) 正常运行。在发布版本中仍作为正常服务运行。 将其与 Christian K. 的上述解决方案结合使用“Environment.UserInteractive”属性,解决方案非常简洁。 OnStartprotected 并且不能修改访问级别:(【参考方案9】:

您也可以通过命令提示符(sc.exe)启动服务。

就我个人而言,我会在调试阶段将代码作为独立程序运行,当大多数错误解决后,改为作为服务运行。

【讨论】:

【参考方案10】:

我以前做的是有一个命令行开关,它可以将程序作为服务或常规应用程序启动。然后,在我的 IDE 中,我将设置开关,以便我可以单步执行我的代码。

对于某些语言,您实际上可以检测它是否在 IDE 中运行,并自动执行此切换。

你使用什么语言?

【讨论】:

【参考方案11】:

使用TopShelf 库。

创建一个控制台应用程序,然后在您的 Main 中配置设置

class Program
    
        static void Main(string[] args)
        
            HostFactory.Run(x =>
            

                // setup service start and stop.
                x.Service<Controller>(s =>
                
                    s.ConstructUsing(name => new Controller());
                    s.WhenStarted(controller => controller.Start());
                    s.WhenStopped(controller => controller.Stop());
                );

                // setup recovery here
                x.EnableServiceRecovery(rc =>
                
                    rc.RestartService(delayInMinutes: 0);
                    rc.SetResetPeriod(days: 0);
                );

                x.RunAsLocalSystem();
            );
        


public class Controller
    
        public void Start()
        

        

        public void Stop()
        

        
    

要调试您的服务,只需在 Visual Studio 中按 F5。

要安装服务,请输入 cmd "console.exe install"

然后您可以在 Windows 服务管理器中启动和停止服务。

【讨论】:

他们的许可太混乱了,无法理解 他们使用 Apache License afaik。 Topshelf 是我用来开发和调试 Windows 服务的最简单的方法。超级容易使用。作为控制台应用程序开发。使用一个命令行开关作为服务安装。强烈推荐。 TopShelf 为我节省了大量时间。谢谢【参考方案12】:

我认为这取决于您使用的操作系统,由于会话之间的分离,Vista 更难附加到服务。

我过去使用的两个选项是:

使用 GFlags(在 Windows 调试工具中)为进程设置永久调试器。这存在于“图像文件执行选项”注册表项中,非常有用。我认为您需要调整服务设置以启用“与桌面交互”。我将它用于所有类型的调试,而不仅仅是服务。 另一种选择是将代码分开一点,以便服务部分可以与正常的应用程序启动互换。这样,您可以使用简单的命令行标志,并作为进程(而不是服务)启动,从而更容易调试。

希望这会有所帮助。

【讨论】:

GFlags +1。如果您无法修改源代码(或者如果您没有源代码),这将特别有用。【参考方案13】:

我希望能够调试我的服务的各个方面,包括 OnStart() 中的任何初始化,同时仍然在 SCM 框架内以完整的服务行为执行它...没有“控制台”或“应用程序”模式.

我通过在同一个项目中创建第二个服务来进行调试。调试服务在正常启动时(即在服务 MMC 插件中)创建服务主机进程。即使您尚未启动真正的服务,这也为您提供了一个附加调试器的过程。将调试器附加到进程后,启动你的真实服务,你可以在服务生命周期的任何地方闯入它,包括 OnStart()。

因为它需要极少的代码侵入,调试服务可以轻松地包含在您的服务设置项目中,并且可以通过注释掉一行代码并删除单个项目安装程序轻松地从您的生产版本中删除。

详情:

1) 假设您正在实施MyService,同时创建MyServiceDebug。将两者都添加到 Program.cs 中的 ServiceBase 数组中,如下所示:

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
         
            new MyService(),
            new MyServiceDebug()
        ;
        ServiceBase.Run(ServicesToRun);
    

2) 将真实服务和调试服务添加到服务项目的项目安装程序中:

当您将服务项目输出添加到服务的设置项目时,这两个服务(真实和调试)都会包含在内。安装后,这两个服务都会出现在 service.msc MMC 插件中。

3) 在 MMC 中启动调试服务。

4) 在 Visual Studio 中,将调试器附加到由调试服务启动的进程。

5) 启动真正的服务,享受调试。

【讨论】:

【参考方案14】:

当我编写服务时,我将所有服务逻辑放在一个 dll 项目中,并创建两个调用该 dll 的“主机”,一个是 Windows 服务,另一个是命令行应用程序。

我使用命令行应用程序进行调试,并将调试器附加到实际服务中,仅针对我无法在命令行应用程序中重现的错误。

如果你使用这种方法,请记住你必须在真实服务中运行时测试所有代码,而命令行工具是一个很好的调试辅助工具,它是一个不同的环境,它的行为与真实服务不完全相同.

【讨论】:

【参考方案15】:

在开发和调试 Windows 服务时,我通常通过添加 /console 启动参数并检查它来将其作为控制台应用程序运行。让生活更轻松。

static void Main(string[] args) 
    if (Console.In != StreamReader.Null) 
        if (args.Length > 0 && args[0] == "/console") 
            // Start your service work.
        
    

【讨论】:

直到您必须调试服务特定问题。 是的,那么您必须将调试器附加到实际的服务进程中。但在大多数情况下,错误都会以任何一种方式出现,开发也容易得多。【参考方案16】:

第一行的Debugger.Break()怎么样?

【讨论】:

【参考方案17】:

为了调试 Windows 服务,我结合了 GFlags 和一个由 regedit 创建的 .reg 文件。

    运行 GFlags,指定 exe 名称和 vsjitdebugger 运行 regedit 并转到 GFlags 设置选项的位置 从文件菜单中选择“导出密钥” 使用 .reg 扩展名将该文件保存在某处 想要调试服务的任何时候:双击 .reg 文件 如果要停止调试,请双击第二个 .reg 文件

或者保存以下 sn-ps 并将 servicename.exe 替换为所需的可执行文件名称。


debugon.reg:

Windows 注册表编辑器版本 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\servicename.exe]
“全球标志”=“0x00000000”
"调试器"="vsjitdebugger.exe"

debugoff.reg:

Windows 注册表编辑器版本 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\servicename.exe]
"GlobalFlag"="0x00000000"

【讨论】:

这仍然适用于 Win 7 / Win 2008 吗?这是support.microsoft.com/kb/824344 的方法,但它依赖于交互式服务,我以为他们被杀了?它一直是我的首选(因为在生产中可能会出现启动问题,在代码中插入 Debugger.Break() 可能不是一种选择)。【参考方案18】:

这是我用来测试服务的简单方法,没有任何额外的“调试”方法和集成的 VS 单元测试。

[TestMethod]
public void TestMyService()

    MyService fs = new MyService();

    var OnStart = fs.GetType().BaseType.GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

    OnStart.Invoke(fs, new object[]  null );


// As an extension method
public static void Start(this ServiceBase service, List<string> parameters)

     string[] par = parameters == null ? null : parameters.ToArray();

     var OnStart = service.GetType().GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

     OnStart.Invoke(service, new object[]  par );

【讨论】:

【参考方案19】:

对于常规的小型编程,我做了一个非常简单的技巧来轻松调试我的服务:

在服务启动时,我检查命令行参数“/debug”。如果使用此参数调用服务,我不会进行通常的服务启动,而是启动所有侦听器并仅显示消息框“调试中,按确定结束”。

因此,如果我的服务以通常的方式启动,它将作为服务启动,如果使用命令行参数 /debug 启动,它将像普通程序一样运行。

在VS中我只添加/debug作为调试参数,直接启动服务程序。

这样我可以轻松调试大多数小问题。当然,有些东西仍然需要作为服务进行调试,但是对于 99% 来说这已经足够了。

【讨论】:

【参考方案20】:
#if DEBUG
    System.Diagnostics.Debugger.Break();
#endif

【讨论】:

【参考方案21】:

我使用了 JOP 答案的变体。使用命令行参数,您可以在 IDE 中使用项目属性或通过 Windows 服务管理器设置调试模式。

protected override void OnStart(string[] args)

  if (args.Contains<string>("DEBUG_SERVICE"))
  
    Debugger.Break();
  
  ...

【讨论】:

【参考方案22】:

对于现有 Windows 服务程序的故障排除,请按照其他人的建议使用“Debugger.Break()”。

对于新的 Windows 服务程序,我建议使用 James Michael Hare 的方法http://geekswithblogs.net/BlackRabbitCoder/archive/2011/03/01/c-toolbox-debug-able-self-installable-windows-service-template-redux.aspx

【讨论】:

【参考方案23】:

只需将调试器午餐放在任何地方并在启动时附加 Visualstudio

#if DEBUG
    Debugger.Launch();
#endif

您还需要以管理员身份启动 VS,并且您需要允许不同用户自动调试进程(如 here 所述):

reg add "HKCR\AppIDE62A7A31-6025-408E-87F6-81AEB0DC9347" /v AppIDFlags /t REG_DWORD /d 8 /f

【讨论】:

【参考方案24】:

使用 Windows 服务模板 C# 项目新建服务应用https://github.com/HarpyWar/windows-service-template

自动检测到控制台/服务模式,自动安装/卸载您的服务以及几个最常用的功能。

【讨论】:

【参考方案25】:
static class Program

    static void Main()
    
        #if DEBUG

        // TODO: Add code to start application here

        //    //If the mode is in debugging
        //    //create a new service instance
        Service1 myService = new Service1();

        //    //call the start method - this will start the Timer.
        myService.Start();

        //    //Set the Thread to sleep
        Thread.Sleep(300000);

        //    //Call the Stop method-this will stop the Timer.
        myService.Stop();

         #else
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
         
            new Service1() 
        ;

        ServiceBase.Run(ServicesToRun);
         #endif
    

【讨论】:

这更容易。只需将解决方案配置设置更改为调试,运行项目/解决方案,随时添加断点。【参考方案26】:

您有两个选项可以进行调试。

    创建一个日志文件:我个人更喜欢单独的日志文件,如文本文件,而不是使用应用程序日志或事件日志。但这会花费您很多时间,因为仍然很难确定我们的确切错误在哪里位置是 将应用程序转换为控制台应用程序:这将使您能够使用我们可以在 VS 中使用的所有调试工具。

请参考我为该主题创建的 THIS 博客文章。

【讨论】:

【参考方案27】:

粘贴

Debugger.Break();

代码中的任何位置。

例如,

internal static class Program
    
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        private static void Main()
        
            Debugger.Break();
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            
                new Service1()
            ;
            ServiceBase.Run(ServicesToRun);
        
    

当你运行你的程序时它会点击Debugger.Break();

【讨论】:

【参考方案28】:

最好的选择是使用“System.Diagnostics”命名空间。

将您的代码包含在调试模式和发布模式的 if else 块中,如下所示,以在 Visual Studio 中的调试和发布模式之间切换,

#if DEBUG  // for debug mode
       **Debugger.Launch();**  //debugger will hit here
       foreach (var job in JobFactory.GetJobs())
            
                //do something 
            

#else    // for release mode
      **Debugger.Launch();**  //debugger will hit here
     // write code here to do something in Release mode.

#endif

【讨论】:

以上是关于调试 Windows 服务的更简单方法的主要内容,如果未能解决你的问题,请参考以下文章

解析 XML 的更简单方法

从附加元素获取 jQuery 对象的更简单方法

对三个数字进行排序的更简单方法

为列映射记录名称的更简单方法?

使用 PHP 动态创建 Javascript 的更简单方法

Spring Boot - GetMapping 到具有不同路径的相同方法的更简单方法