【问题标题】:Debugging a Windows Service - Prevent Cannot Start Service调试 Windows 服务 - 防止无法启动服务
【发布时间】:2017-03-07 21:32:17
【问题描述】:

尝试调试一个windows服务(去掉了安装、编码、安装、编码等的需要),以为找到了解决办法

class Program
{
    static void Main(string[]args) 
    {
        ClientService service = new ClientService();

        if (args.Length > 0) 
        {
            Task.Factory.StartNew(service.Main, TaskCreationOptions.LongRunning);

            Console.WriteLine("running...");
            Console.ReadLine();

        }
        else 
        {
#if (!DEBUG)
            ServiceBase[]ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new MyService()
            };
            ServiceBase.Run(ServicesToRun);
# else
            ServiceBase.Run(service);
        }
# endif
    }
}

但是我仍然收到错误:

无法从命令行或调试器启动服务。必须首先安装 Windows 服务(使用 installutil.exe),然后使用 ServerExplorer、Windows 服务管理工具或 NET START 命令启动。

任何想法我需要更改以避免提示?

【问题讨论】:

  • 在项目的调试属性选项卡中传递命令行参数。任何参数都可以。不要在不理解代码的情况下复制粘贴代码。
  • 当您在谷歌上搜索该错误消息文本时,谷歌结果是什么意思?
  • @David 此代码是众多实例之一,其中不是通过ServiceBase.Run(),服务类实际上是通过用户代码启动的,以便在不安装服务的情况下调试服务。如果args.Length > 0,此代码会执行此操作。这就像谷歌第一次点击“C# debug windows service without installed”。完全不需要安装 Windows 服务来调试它的逻辑。
  • @CodeCaster:有趣,我从未见过使用过这种方法。说得通。我想我从来没有遇到过这个问题,因为我的服务代码一直是独立可运行/可测试的,而无需运行服务主机本身。 (我上次遇到此错误消息是很久以前在维护遗留系统时,该过程是无论如何都要在开发机器上安装和运行服务。)
  • @David 哦,当然,如果你真的需要这个,那你就错了。

标签: c#


【解决方案1】:

您从Running Windows Service Application without installing it 复制了代码,但它被设计破坏并且您错误地更改了它。

其背后的想法是,您有一个 ServiceBase-inheriting 类,其中包含一个执行实际服务逻辑的公共方法:

public class MyService : ServiceBase
{
    public void DoTheServiceLogic()
    {
        // Does its thing
    }

    public override void OnStart(...)
    {
        DoTheServiceLogic();
    }
}

然后在你的应用程序中,你可以这样启动它:

class Program
{
    static void Main(string[] args)
    {
        ServiceBase[] ServicesToRun = new ServiceBase[] 
        { 
            new MyService() 
        };

        ServiceBase.Run(ServicesToRun);
    }
}

这提供了一个可以作为 Windows 服务安装的可执行应用程序。

但是你不想安装你的服务然后附加 Visual Studio 来调试它;这是一个非常低效的工作流程。

所以你发现的代码尝试做的,就像网上的许多方法一样,是用一个特定的命令行标志启动应用程序,比如/debug,然后调用服务逻辑上的公共方法 - 实际上没有将其作为 Windows 服务运行

可以这样实现:

class Program
{
    static void Main(string[] args)
    {

        if (args.Length == 1 && args[0] == "/debug")
        {
            // Run as a Console Application
            new MyService().DoTheServiceLogic();
        }
        else
        {
            // Run as a Windows Service
            ServiceBase[] ServicesToRun = new ServiceBase[] 
            { 
                new MyService() 
            };

            ServiceBase.Run(ServicesToRun);
        }
    }
}

现在您可以指示 Visual Studio 在调试应用程序时传递/debug 标志,如MSDN: How to: Set Start Options for Application Debugging 中所述。

这稍微好一点,但仍然是一个糟糕的方法。您应该完全提取服务逻辑,并编写单元测试以便能够测试您的逻辑,而不必在应用程序中运行它,更不用说 Windows 服务了。

【讨论】:

    【解决方案2】:

    从改变你的代码开始:

    static void Main(string[] args)
    {
    #if DEBUG // If you are currently in debug mode
        ClientService service = new ClientService (); // create your service's instance
        service.Start(args); // start this service
        Console.ReadLine(); // wait for user input ( enter key )
    #else // else you're in release mode
        ServiceBase[] ServicesToRun; // start service normally
        ServicesToRun = new ServiceBase[] 
        { 
            new MyService() 
        };
        ServiceBase.Run(ServicesToRun);
    #endif
    }
    

    在您的服务中添加此方法:

    public void Start(string[] args)
    {
        OnStart(args);
    }
    

    现在您只需将属性更改应用程序类型从Windows Application 更改为Console Application

    【讨论】:

      【解决方案3】:

      你可以这样做:

      创建一个与旅游服务同名的部分类:

       public partial class AlertEngineService
          {
              public void Run(string[] args)
              {
      
                  OnStart(args);
                  Console.WriteLine("Press any key to stop program alert engine service");
                  Console.Read();
                  OnStop();
              }
          }
      }
      

      并在调试时调用此命令:

      var servicesToRun = new ClientService ();
      servicesToRun.Run(args);
      

      您还可以更改服务配置以作为控制台运行(在属性部分中)。

      希望对你有帮助

      【讨论】:

        【解决方案4】:

        在 Program.cs 中

        class Program
        {
            static void Main(string[] args)
            {
                #if DEBUG
                new ClientService().Start();
                Thread.Sleep(Timeout.Infinite); //Ensure your service keeps running             
                #else
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[] 
                { 
                    new MyService() 
                };
                ServiceBase.Run(ServicesToRun);
                #endif
            }
        }
        

        在 ClientService.cs 中

        public void Start()
        {
            OnStart(null);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多