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


当前回答

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
    }
}

其他回答

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

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

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

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

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

当我几周前建立一个新的服务项目时,我发现了这个帖子。虽然有很多很好的建议,但我仍然没有找到我想要的解决方案:在不修改服务类的情况下调用服务类的OnStart和OnStop方法的可能性。

我想到的解决方案是利用环境。交互式选择运行模式,正如这篇文章的其他答案所建议的。

static void Main()
{
    ServiceBase[] servicesToRun;
    servicesToRun = new ServiceBase[] 
    {
        new MyService()
    };
    if (Environment.UserInteractive)
    {
        RunInteractive(servicesToRun);
    }
    else
    {
        ServiceBase.Run(servicesToRun);
    }
}

RunInteractive helper使用反射来调用受保护的OnStart和OnStop方法:

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

这是所需的所有代码,但我还编写了带有解释的演练。

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

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

如果我想快速调试服务,我只需在那里放入一个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 */
}

在那里,代码将只在调试构建期间启用。在此过程中,为服务调试创建一个单独的Build Configuration可能会很有用。