问与答 调试Windows服务?

webster · 2020-03-06 13:55:18 · 热度: 20

我阅读了有关该主题的MSDN文章。 去引用:

因为服务必须从   在服务范围内   控制管理中心,而不是来自   在Visual Studio中,调试   服务不如简单   调试其他Visual Studio   应用程序类型。 要调试服务,   您必须启动服务,然后   将调试器附加到该进程中   它正在运行。 那你可以   使用以下所有 工具 调试应用程序   标准调试功能   Visual Studio。

现在我的问题是我的服务最初无法启动。 首先它崩溃了,并说:

未处理的异常   (System.Runtime.InteropServices.COMException)   发生在MyServiceName.exe [3596]中)

并建议我对其进行调试(选择该调试器实例会立即崩溃)。 然后说

无法启动MyServiceName   本地计算机上的服务。 错误   1053:服务未响应   启动或控制请求   适时的时尚

因此,如何调查/调试服务无法启动的原因? 问题是我创建了一个控制台应用程序,该控制台应用程序完全可以执行该服务,并且可以正常工作。 (我的意思是我只是将OnStart744()方法和主循环的内容复制到了main中)。

任何帮助,将不胜感激。

该服务使用C#编写,大量使用互操作。 我正在使用VS2008

猜你喜欢:
共收到 15 条回复
barret #1 · 2020-03-06 13:55:18

您可以使用参数来让您的应用决定是作为服务启动还是作为常规应用启动(即在这种情况下,显示表单或启动服务):

static void Main(string[] args)
{
    if ((1 == args.Length) && ("-runAsApp" == args[0]))
    {
        Application.Run(new application_form());
    }
    else
    {
        System.ServiceProcess.ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] { new MyService() };
        System.ServiceProcess.ServiceBase.Run(ServicesToRun);
    }
}

现在,如果您传递参数“ -runAsApp”,则可以正常调试应用程序-SCM不会传递此参数,因此您也可以将其用作服务而无需进行任何代码更改(前提是您衍生自ServiceBase

编辑:

Windows服务的另一个区别是身份(对于InterOp来说尤其重要)-您要确保在“应用”模式和服务模式下都以相同的身份进行测试。

为此,您可以在应用程序模式下使用模拟(如果有帮助,我可以发布一个C#包装器,但是可以很容易地用谷歌搜索),以使用与Windows服务将在WindowsService运行的相同身份(通常是LocalService或NetworkService)。

如果需要其他身份,则可以将设置添加到app.config中,以使您可以决定是否使用凭据,以及如果要模拟的用户,则这些设置将作为应用程序运行时处于活动状态,但对于Windows服务已关闭( 因为该服务已经以所需的身份运行):

  <appSettings>
    <add key="useCredentials" value="false"/>
    <add key="user" value="Foo"/>
    <add key="password" value="Bar"/>
  </appSettings>
harvey #2 · 2020-03-06 13:55:20

我通常只是手动设置一个断点,然后将其指向c#中当前打开的项目。 设置断点的代码是:

System.Diagnostics.Debugger.Break();

那应该使您入门,然后您可以单步执行代码并查看实际情况。

joshua #3 · 2020-03-06 13:55:21

我是从劳伦斯·文纳姆(C. Lawrence Wenham)那里偷来的,所以我不能真正相信,但是您可以使用以下代码以编程方式将调试器附加到服务,而无需中断执行:

System.Diagnostics.Debugger.Launch();

将其作为第一行放在服务的OnStart()方法中,它将提示您选择VS的实例以附加其调试器。 从那里,系统将在您设置的断点处停止,并在抛出异常时停止。 我会在代码周围放一个#if DEBUG子句,以便Release版本不会包含它。 或者您可以在发现问题后将其清除。

shahid #4 · 2020-03-06 13:55:22

您可以使用WinDbg / NTSD(“ Windows调试工具”软件包中的另一个调试器)与服务一起启动调试器。

为此,在“映像文件”选项卡中打开“ gflags”(在上述软件包中也可用),并为映像文件(服务)设置调试器可执行文件的路径;

如果您的服务被标记为交互式(仅当它在SYSTEM帐户下运行时才可能),您可以直接启动WinDbg,只需将调试器设置为“ PATH_TO_WINDBG \ windbg.exe -g -G”(-g / -G是 以便调试器在应用程序启动或结束时不会中断执行-默认行为)。 现在,当启动服务时,windbg窗口应该会弹出,并会捕获任何未处理的异常。

如果您的服务不是交互式的,则可以在远程模式下启动NTSD调试器(命令行调试器),然后从WinDbg(甚至可以在另一台PC上运行)连接到它。 为此,将调试器的gflags设置为“ PATH_TO_NTSD \ ntsd -remote tcp:port = 6666,server = localhost”。 然后通过使用诸如“ windbg -remote tcp:port = 6666,server = localhost”之类的东西启动windbg连接到远程调试器,您应该完全控制其他调试会话。

至于查找异常本身的源代码,这里是一个windbg教程,但是作为开始,尝试在捕获到异常之后执行“!analyze -v”命令-运气好的话,这是您所需要的所有信息。 。

注意:对于您的情况来说,这可能是过高的,但是通过这种方法,您甚至可以在系统启动期间调试服务(我曾经遇到过服务的计时问题,只有在首次启动系统时才出现问题)

quinton #5 · 2020-03-06 13:55:24

我做的一件事(可能有点像hack)是在我的ex.ToString()073方法的开始处放了一个ex.Message。 这给了我10秒的窗口,可将调试器附加到服务,然后再执行其他任何操作。

当然,调试完成后,我将删除ex.Message语句。

您可能要做的另一件事是:

public override void OnStart()
{
    try
    {
        // all your OnStart() logic here
    }
    catch(Exception ex)
    {
        // Log ex.Message
        if (!EventLog.SourceExists("MyApplication"))
            EventLog.CreateEventSource("MyApplication", "Application");

        EventLog.WriteEntry("MyApplication", "Failed to start: " + ex.Message);
        throw;
    }
}

当您登录ex.Message时,您可能会收到更详细的错误消息。 此外,您只需登录ex.ToString()即可获取整个堆栈跟踪信息,并且如果您的.pdb文件与可执行文件位于同一目录中,它甚至会告诉您发生异常的行。

abner #6 · 2020-03-06 13:55:25

在OnStart中添加许多详细的日志记录。 这是痛苦的,古老的学校,但是行得通。

trever #7 · 2020-03-06 13:55:27

似乎问题出在用户上下文上。 让我确认我的假设是否正确。

  1. 当您说代码可以从控制台应用程序完美运行时,我假设您正在以登录的同一用户身份执行控制台应用程序。

  2. 当您说从Windows服务调用时相同的代码崩溃时,我认为该服务正在您的开发计算机中的“本地系统”帐户中运行。

如果我的假设都正确,请尝试以下步骤。

  1. 在服务列表中,右键单击您的服务,选择属性,然后选择“登录”选项卡。

  2. 选择选项“此帐户”并提供现有的用户名和密码。

  3. 现在尝试启动该服务。 现在应该开始,没有任何错误。

以下可能是您错误的根本原因

  1. 如果使用的是SQL Server,请确保未使用SSPI身份验证。

  2. 如果您尝试读取使用“本地系统”帐户时没有权限的任何共享文件夹\资源。

  3. 如果应用程序所需的任何必需依赖项都位于“本地系统”用户没有访问权限的其他文件夹中。

  4. 如果您使用的VBA自动化在“本地系统”帐户中不起作用。

  5. 尝试禁用防火墙或防病毒软件。

tion #8 · 2020-03-06 13:55:28

您可以在互操作调用周围添加一些日志记录,以找出哪个失败。

默认情况下,服务也不与桌面相关联。 如果打开services.msc控制面板小程序,则获取服务的属性,请转到“登录”选项卡,可以选中“允许服务与桌面交互”。 在某些情况下,这可以为您解决问题。

ternence #9 · 2020-03-06 13:55:30

我认为原因可能是由于互操作性的大量使用引起的。 因此,您需要以不同的方式解决此问题。 我建议您使用与您的服务相同的逻辑来创建Windows或控制台应用程序,并确保它首先运行时没有任何问题,然后您可能要继续创建Win服务。

terence #10 · 2020-03-06 13:55:31

调试服务是一件痛苦的事情,特别是因为启动似乎是在出现许多问题的时候(至少对我们而言)。

我们通常要做的是将尽可能多的逻辑提取到具有start和stop方法的单个类中。 这些类方法是服务直接调用的所有方法。 然后,我们创建一个具有两个按钮的WinForm应用程序:一个调用启动,另一个调用停止。 然后,我们可以直接从调试器运行WinForm应用程序,看看发生了什么。

这不是最优雅的解决方案,但对我们有用。

carman #11 · 2020-03-06 13:55:32

请查看此问题,该问题讨论了如何在窗口服务中捕获未处理的异常。

jeff #12 · 2020-03-06 13:55:34

为了将调试器附加到Windows服务,需要首先启动它。 可以在Windows事件日志中检查服务无法启动的原因。

之后,从Visual Studio调试->附加到进程中,附加调试器的过程非常简单。

frances #13 · 2020-03-06 13:55:35

我所做的工作由OnStart()实现,如下所示:

_myBusinessObject = new MyBusinessObject();

构造业务对象后,计时器和IPC处理程序将完成所有实际(服务)工作。

这样,您就可以创建一个Forms / WPF应用程序,该应用程序在Form_Loaded处理程序中调用上面的相同代码。 这样,调试Forms应用程序与调试Service完全相同。

唯一的问题是,如果您使用的是app.config值,则将有另一个需要更新的app.config文件。

travon #14 · 2020-03-06 13:55:37

在Service OnStart方法中使用以下代码:

System.Diagnostics.Debugger.Launch();

从弹出消息中选择Visual Studio选项

timmi #15 · 2020-03-06 13:55:38

阅读此处提到的2篇文章:

[HTTP://geek是with blog上.net/black rabbit coder/archive/2011/03/01/从-toolbox-debug-able-self-installable-Windows-service-template-热镀锌.aspx]

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册