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


当前回答

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


简单的回答是,我使用以下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 7x64和Visual Studio 2010 Team Edition,但也适用于其他(更新的)环境。


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

因为调试器。启动代码,这将导致一个对话框“一个未处理的Microsoft . net Framework异常发生在Servicename.exe.”出现。单击“是”,调试Servicename.exe,如下图所示:


之后,Windows UAC可能会提示您输入管理凭据。输入它们并继续执行Yes:

之后,著名的Visual Studio即时调试器窗口出现。它询问您是否要使用已删除的调试器进行调试。在单击Yes之前,选择不想打开新实例(第二个选项)——在这里,新实例没有帮助,因为不会显示源代码。所以你选择之前打开的Visual Studio实例:

单击Yes后,过一会儿Visual Studio将在调试器所在的行中显示黄色箭头。启动语句,您可以调试您的代码(方法MyInitOnStart,其中包含初始化)。

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

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



请注意,

If you build a Release, then the debug code is automatically removed and the service runs normally. I am using Debugger.Launch(), which starts and attaches a debugger. I have tested Debugger.Break() as well, which did not work, because there is no debugger attached on start up of the service yet (causing the "Error 1067: The process terminated unexpectedly."). RequestAdditionalTime sets a longer timeout for the startup of the service (it is not delaying the code itself, but will immediately continue with the Debugger.Launch statement). Otherwise the default timeout for starting the service is too short and starting the service fails if you don't call base.Onstart(args) quickly enough from the debugger. Practically, a timeout of 10 minutes avoids that you see the message "the service did not respond..." immediately after the debugger is started. Once you get used to it, this method is very easy because it just requires you to add 4 lines to an existing service code, allowing you quickly to gain control and debug.

其他回答

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

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

因此,如果我的服务以通常的方式启动,它将作为服务启动,如果它以命令行参数/调试启动,它将像正常程序一样工作。

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

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

下面是我用来测试服务的简单方法,没有任何额外的“调试”方法,并带有集成的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 });
}

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

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

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

使用Windows Service Template c#项目创建一个新的服务应用程序https://github.com/HarpyWar/windows-service-template

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

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

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

Use GFlags (in the Debugging Tools for Windows) to setup a permanent debugger for a process. This exists in the "Image File Execution Options" registry key and is incredibly useful. I think you'll need to tweak the Service settings to enable "Interact with Desktop". I use this for all types of debugging, not just services. The other option, is to separate the code a bit, so that the service part is interchangable with a normal app startup. That way, you can use a simple command line flag, and launch as a process (rather than a Service), which makes it much easier to debug.

希望这能有所帮助。