代码之家  ›  专栏  ›  技术社区  ›  Nathan

如何调试.NET Windows服务OnStart方法?

  •  52
  • Nathan  · 技术社区  · 16 年前

    我在.NET中编写的代码只有在作为Windows服务安装时才会失败。故障甚至不允许服务启动。我不知道如何进入OnStart方法。

    How to: Debug Windows Service Applications 给出了诱人的线索:

    附加到服务的进程允许您调试服务的大部分(但不是全部)代码;例如,由于服务已经启动,因此不能以这种方式调试服务的OnStart方法中的代码,也不能调试用于加载服务的主方法中的代码。 解决此问题的一种方法是在服务应用程序中创建一个临时的第二个服务,该服务的存在只是为了帮助调试。您可以安装这两个服务,然后启动这个“虚拟”服务来加载服务进程。 一旦临时服务启动了该进程,就可以使用Visual Studio中的“调试”菜单附加到该服务进程。

    但是,我不清楚您应该如何创建虚拟服务来加载服务进程。

    16 回复  |  直到 8 年前
        1
  •  93
  •   palehorse    16 年前

    作为临时解决方案,您可以做的一件事是启动调试器作为OnStart中的第一行代码。

    System.Diagnostics.Debugger.Launch()
    

    这将提示您输入要使用的调试器。只需在Visual Studio中打开解决方案并从列表中选择该实例即可。

        2
  •  10
  •   HasaniH    16 年前

    我倾向于添加这样的方法:

        [Conditional("DEBUG")]
        private void AttachDebugger()
        {
            Debugger.Break();
        }
    

    它将只在项目的调试版本上被调用,并且它将暂停执行并允许您附加调试器。

        3
  •  8
  •   Contango    12 年前

    一旦您安装了使用 installutil.exe ,您可以更改 Start Parameters 要在服务启动时跳转到调试器,请执行以下操作:

    enter image description here

    使用参数手动启动服务时 -debugWithVisualStudio (或者简单地 -d ,它将自动检测正确的项目,并在Visual Studio中启动交互式调试器:

    enter image description here

    要支持此功能,请更改服务的 OnStart() 功能:

    /// <summary>
    ///     Executed when the service is started.
    /// </summary>
    /// <param name="args">Command line arguments.</param>
    protected override void OnStart(string[] args)
    {
        try
        {
            //How to debug when running a Windows Service:
            // 1. Right click on the service name in Windows Service Manager.
            // 2. Select "Properties".
            // 3. In "Start Parameters", enter "-d" (or "-debugWithVisualStudio").
            // 4. Now, when you start the service, it will fire up Visual Studio 2012 and break on the line below.
            // 5. Make sure you have UAC (User Access Control) turned off, and have Administrator privileges.
    #if DEBUG
            if (((ICollection<string>)args).Contains("-d")
                || ((ICollection<string>)args).Contains("-debugWithVisualStudio"))
            {
                Debugger.Launch(); // Launches VS2012 debugger.
            }
    #endif
            ShellStart(args);
            base.OnStart(args);
        }
        catch (Exception ex)
        {
            // Log exception here.
        }
    }
    

    (可选)如果要缩小到服务引发错误的确切代码行,请从Visual Studio菜单中打开异常。 DEBUG .. Exceptions . 当您继续调试时,它将在引发异常的确切行上中断。

    enter image description here

        4
  •  7
  •   Francis B.    14 年前

    它工作得很好!

    protected override void OnStart(string[] args)
    {
        System.Diagnostics.Debugger.Launch();
    }
    
        5
  •  5
  •   Boris Hurinek    12 年前

    上面的选项在Windows 8上似乎不起作用。

    我在onStart()方法中添加了thread.sleep(15000);并在代码的下一行设置了断点。这给了我15秒的时间在启动服务后将vs调试器附加到我的进程中,并允许我很好地调试onstart()方法。

        6
  •  4
  •   waterlooalex    16 年前

    您可以添加这样的代码行:

    System.Diagnostics.Debugger.Break()
    

    它将弹出一个窗口,提示您选择要使用哪个调试器进行调试,例如允许您附加到Visual Studio并单步执行代码。

    见:

    http://msdn.microsoft.com/en-us/library/system.diagnostics.debugger.break.aspx

        7
  •  2
  •   Ryan Kohn uday    14 年前

    可以为作为控制台应用程序运行的Windows服务设置一个配套项目,但可以使用反射访问服务方法。有关详细信息和示例,请参见此处: http://ryan.kohn.ca/articles/how-to-debug-a-windows-service-in-csharp-using-reflection/ .

        8
  •  2
  •   Chirag    10 年前

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

    System.Diagnostics.Debugger.Launch();
    

    从弹出消息中选择Visual Studio选项。记住以管理员身份运行Visual Studio。

    注意:要仅在调试模式下使用它,如果可以使用调试编译器指令,如下所示。这将防止在发布模式下在生产服务器上发生意外或调试。

    #if DEBUG
        System.Diagnostics.Debugger.Launch();
    #endif
    
        9
  •  2
  •   Community CDub    8 年前

    正如其他人指出的,您必须向onStart方法添加一个调试器中断:

    #if DEBUG
        System.Diagnostics.Debugger.Break()
    #endif
    

    同时以管理员身份启动VisualStudio并允许由其他用户自动调试进程(如所述 here ):

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

    (我在这里也解释了这一点: https://stackoverflow.com/a/35715389/5132456 )

        10
  •  1
  •   Coach David    12 年前

    我知道这很晚了,但这是我们处理Windows服务调试的方法

    首先创建一个将充当服务的类。

    添加适当的启动、停止、暂停等方法。

    将Windows窗体添加到服务项目。

    在服务代码中,创建上面创建的服务类,并进行在ServiceBase类中启动和停止服务所需的调用。

    打开program.cs并添加以下内容

    #if DEBUG
        [STAThread]
    #endif
        static void Main()
        {
    try
            {
    #if DEBUG
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new DebugForm());
    #else
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[] 
            { 
                new YourWindowsService() 
            };
                ServiceBase.Run(ServicesToRun);
    #endif
            }
            catch (Exception e)
            {
                logger.Error(DateTime.Now.ToString() + " - " + e.Source + " - " + e.ToString() + "\r\n------------------------------------\r\n");
            }
    }
    

    在调试模式下运行时,Windows窗体将启动。完成后请记住在发布模式下构建。当然,条件编译变量可以是您喜欢的任何东西。甚至可以创建单独的项目,这样调试表单就是它自己的项目。

    希望这有帮助

        11
  •  1
  •   Abhishek Srivastava    12 年前

    你也可以试试 System.Diagnostics.Debugger.Launch()。 方法。它有助于将调试器指针移到指定的位置,然后您可以调试代码。

    在此步骤之前 请安装service.exe 使用Visual Studio命令提示的命令行- InstallUtil项目服务.exe

    然后从 控制面板->管理工具->计算机管理->服务和应用程序->服务->您的服务名称

        12
  •  1
  •   and... break    11 年前

    如果在onStart方法中添加debugger.launch(),但它不起作用,那么可能会出现与我相同的问题,即,异常发生在构造函数中,因此永远不会调用onStart。(头拍)

    (很抱歉,如果这应该是对别人答案的评论,但我没有足够的可信度发表评论)

        13
  •  0
  •   Dror Helper    16 年前

    尝试添加调试器。在有问题的方法中中断。当服务启动时,将引发异常,寡妇应提供使用Visual Studio进行调试。

        14
  •  0
  •   Matt    16 年前

    我通常有一个控制台应用程序,它假装是SCM,例如,调用start、stop,然后我可以将其作为主要的编码/调试目的,并使用debugger.break进行调试,当服务通过SCM安装和启动后。

    这意味着要开始做更多的工作,我有一个包含所有服务代码的类库,这个类公开了Windows服务类和控制台应用程序都可以调用的启动和停止。

    马特

        15
  •  0
  •   Mubashar    11 年前

    在我讨论这个话题之前,有一个建议。如果您是服务器端开发人员,请务必特别使用日志。因为在Visual Studio中调试代码时可能无法产生某些条件。

    回到主题,我使用envoirnment.userInteractive标志这非常方便,请参阅下面的代码

    public static void Main(string[] args)
    {
    
        if (System.Environment.UserInteractive)
        {
            string parameter = string.Concat(args);
    
            switch (parameter)
            {
                case "--install":
                    ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
                    break;
                case "--uninstall":
                    ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
                    break;
                default:
                    WindowsService service = new WindowsService();
                    service.OnStart(args);
                    Console.ReadKey();
                    service.OnStop();
                    break;
            }
        }
        else
        {
            ServiceBase.Run(new WindowsService());
        }
    }
    

    从Visual Studio中,您将获得用户交互标志集,以便我将其作为控制台应用程序运行,此外,如果您想测试产品构建,还可以通过双击产品构建并附加调试器来运行它。

        16
  •  0
  •   Admiral Ackbar    9 年前

    我有一个有趣的方法来完成这个任务,我添加了另一个名为debugonService的配置

      <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugNoService|AnyCPU' ">
        <OutputPath>.\</OutputPath>
        <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
        <BaseAddress>285212672</BaseAddress>
        <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
        <ConfigurationOverrideFile>
        </ConfigurationOverrideFile>
        <DefineConstants>DEBUG;TRACE;DEBUGNOSERVICE</DefineConstants>
        <DocumentationFile>
        </DocumentationFile>
        <DebugSymbols>true</DebugSymbols>
        <FileAlignment>4096</FileAlignment>
        <NoStdLib>false</NoStdLib>
        <NoWarn>
        </NoWarn>
        <Optimize>false</Optimize>
        <RegisterForComInterop>false</RegisterForComInterop>
        <RemoveIntegerChecks>false</RemoveIntegerChecks>
        <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
        <WarningLevel>4</WarningLevel>
        <DebugType>full</DebugType>
        <ErrorReport>prompt</ErrorReport>
        <UseVSHostingProcess>false</UseVSHostingProcess>
      </PropertyGroup>
    

    我使用if指令。 项目安装程序.cs

    #if !DEBUGNOSERVICE    
       static void Main()
       {
          System.ServiceProcess.ServiceBase[] ServicesToRun;
          .....
       }
    #endif
    

    我添加了一个Windows窗体,还将Windows窗体包装在

    #if DEBUGNOSERVICE
    ...
    static void Main() 
    {
        Form     form;
    
        Application.EnableVisualStyles();
        Application.DoEvents();
    
        form = new <the name of the form>();
    
        Application.Run(form);
    }
    ...
    #endif
    

    根据所选的配置,代码可以作为易于调试的Windows窗体应用程序运行,也可以作为服务运行。

    如果看起来像很多工作,但它一直工作,使调试代码非常容易。您可以将所有类型的输出添加到表单中,以便观察它的运行。

    推荐文章