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


当前回答

使用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服务管理器中启动和停止服务。

其他回答

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

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

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
}

当我几周前建立一个新的服务项目时,我发现了这个帖子。虽然有很多很好的建议,但我仍然没有找到我想要的解决方案:在不修改服务类的情况下调用服务类的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);
}

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

我喜欢能够调试我的服务的每个方面,包括在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)将真实服务和调试服务添加到服务项目的项目安装程序中:

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

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

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

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

只是粘贴

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();当你运行程序时。