.NET的Windows服务是否需要调用ServiceBase.Run()?

4

我在处理Windows服务方面还比较新,但我发现了一个奇怪的问题,希望能得到一些澄清。我有一个用C#编写的Windows服务,我使用命令行安装和启动它(在stackoverflow上找到了很好的说明)。我的服务的主要方法如下:

    static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            ServiceBase.Run(new MyServiceName());
        }
        else if (args.Length == 1)
        {
            const string name = "MyServiceName";
            Type type = typeof(MyAssembly);
            switch (args[0])
            {
                case "-install":
                    ServiceUtils.InstallService(name, type);
                    ServiceUtils.StartService(args, name);
                    break;
                case "-uninstall":
                    ServiceUtils.StopService(name);
                    ServiceUtils.UninstallService(name, type);
                    break;
                default:
                    throw new NotImplementedException();
            }
        }
    }

当我调试时,我总是向应用程序发送一个参数(-install)。因此,第一个if语句(if (args.Length == 0))永远不会执行。这是预期的,我的服务已经成功安装和启动。然而,如果我删除该if语句并只保留if (args.Length == 1)语句,则我的服务可以正确安装但无法启动,并出现以下错误:
“在计算机“。”上无法启动MyServiceName。”
我的问题是:为什么在我的应用程序中从未执行第一个if语句的代码是必需的?
以下是InstallService和StartService方法的支持代码(也是我从stackoverflow获取的):
    public static void InstallService(string serviceName, Type t)
    {
        if (IsInstalled(serviceName)) return;

        try
        {
            Assembly a = t.Assembly;
            using (AssemblyInstaller installer = GetInstaller(a))
            {
                IDictionary state = new Hashtable();
                try
                {
                    installer.Install(state);
                    installer.Commit(state);
                }
                catch
                {
                    try
                    {
                        installer.Rollback(state);
                    }
                    catch
                    { }
                    throw;
                }
            }
        }
        catch
        {
            throw;
        }
    }

    public static void StartService(string[] args, string serviceName)
    {
        if (!IsInstalled(serviceName)) return;

        Console.WriteLine("Service is installed.  Attempting to start service.");

        ServiceController sc = new ServiceController();
        sc.ServiceName = serviceName;

        if (sc.Status == ServiceControllerStatus.Stopped)
        {
            Console.WriteLine("Starting {0}: ", sc.ServiceName);
            try
            {
                sc.Start(args);
                sc.WaitForStatus(ServiceControllerStatus.Running);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
3个回答

9

第一个if语句(if (args.Length == 0))是永远不会被执行的

这并不正确,它确实会被执行。由ServiceController.Start()执行。您看不到这一点,因为服务控制器会再次启动您的EXE,创建另一个进程,这次是服务进程,而不是控制台进程。这个进程您无法附加调试器。如果删除该if语句,则服务在启动后立即退出。服务控制器将使用“无法启动MyServiceName”异常消息进行正确的投诉。


1
if (args.Length == 0)
{            
    ServiceBase.Run(new MyServiceName());
}

当服务控制器启动服务时,会运行此代码,因为服务控制器不会将任何参数传递给Main()。

如果您不执行ServiceBase.Run(new MyServiceName()),则您的服务将无法响应来自服务控制器的任何命令,并且您会看到类似于错误的错误信息。


我实际上正在使用string[]启动ServiceController.Start()。 它有一个重载。[链接]http://msdn.microsoft.com/en-us/library/9c38b683.aspx。你是说无论我是否首先使用参数启动我的应用程序,我总是需要在main中提供一个带0个参数的入口点吗? - my_overflowed_stack
是的。您需要使用该exe中服务列表调用ServiceBase.Run()才能使服务正常工作,并且您不希望在任何其他情况下调用它。 - Andrew Barber

0

Main()仍然是应用程序的入口点。该进程作为启动服务之外的单独步骤启动。

实际上,可以在同一进程中运行多个服务,这种处理方式使其成为可能。也就是说...不仅仅是相同的exe程序,而且实际上在同一运行进程中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接