C# 为什么在服务启动时调用Main()方法?

C# 为什么在服务启动时调用Main()方法?,c#,service,windows-services,C#,Service,Windows Services,我有一个带有一个主类的应用程序,它重写ServiceBase方法,并具有main()静态方法。 当命令行调用Main()方法时,我想使用它;当从windows服务管理调用它时,我想使用OnStart()/OnStop() 我使用installutils成功地将此应用程序作为服务安装,但当我启动它时,会调用Main()方法,而不是按预期调用OnStart() using System; using System.Collections.Generic; using System.IO; using

我有一个带有一个主类的应用程序,它重写ServiceBase方法,并具有main()静态方法。 当命令行调用Main()方法时,我想使用它;当从windows服务管理调用它时,我想使用OnStart()/OnStop()

我使用installutils成功地将此应用程序作为服务安装,但当我启动它时,会调用Main()方法,而不是按预期调用OnStart()

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Xml.Serialization;
using System.Runtime.Serialization.Json;
using System.Threading;
using System.ServiceProcess;
using System.Configuration.Install;
using System.Reflection;

namespace Test
{

    class Program : ServiceBase
    {

        static void Main(string[] args)
        {  
            log.Error("Run as App");
        }


        protected override void OnStart(string[] args)
        {
            log.Info("Starting service");
        }

        protected override void OnStop()
        {
            log.Info("Stopping service");
        }
    }


}

Windows服务有一个有罪的秘密。他们的生活开始于普通的旧控制台应用程序。只有在它们开始运行并向服务控制管理器注册之后,它们才会转换为服务

因此,是的,
Main
是第一个被调用的入口点,这是正确的,因为在这一点上,它只是一个控制台应用程序


服务向服务控制管理器注册并成为服务的方式是通过从
Main
方法(或它调用的方法)调用
ServiceBase.Run()
来处理的。Main方法也会在服务中被调用,就像在任何其他程序中一样。(见附件)

您可以使用属性
Environment.UserInteractive
()确定应用程序是由用户调用的还是作为服务调用的。

以下是答案:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Xml.Serialization;
using System.Runtime.Serialization.Json;
using System.Threading;
using System.ServiceProcess;
using System.Configuration.Install;
using System.Reflection;

namespace Test
{

    class Program : ServiceBase
    {

        static void Main(string[] args)
        {  
                if (System.Environment.UserInteractive)
                {
                    log.Debug("App");
                }
                else
                {
                    ServiceBase.Run(new ServiceBase[] { new Program() });
                }
        }


        protected override void OnStart(string[] args)
        {
            log.Info("Starting service");
        }

        protected override void OnStop()
        {
            log.Info("Stopping service");
        }
    }


}

当Environment.UserInteractive为false时,是否应该运行ServiceBase.run()?似乎ServiceBase.Run()需要一个服务数组作为参数,我应该传递什么?@Tobia-通常,您会传递一个类的实例,该类具有
OnStart
OnStop
方法。它需要一个数组,因为服务进程实际上可以支持/包含多个服务。如果您在VS中创建了一个新的服务项目,它会自动为您设置。以
UserInteractive
为轴心是一种非常常见的区分方式(但不一定100%万无一失——什么都不是),我不知道这是否是一个肮脏的秘密,因为这是一个明显的、有充分文件证明的表现,几乎所有独立的可执行程序都是如何工作的(相对于可链接的库)。编译器将程序的入口点设置为main()方法或其重载之一。除此之外,还取决于程序在任何外部上下文(服务控制管理器)中注册自身,并保持自身运行(而不是脱离main()方法并终止)。@Craig-可以想象,操作系统对以不同方式启动不同类型的二进制文件具有“本机”支持。当然,托管入口点与实际入口点相差甚远。NET本可以将所有的服务机制都隐藏在幕后,并假装OnStart/OnStop等是服务托管代码部分的实际入口点。但他们没有,并命名了一个不同的操作系统。当然,这是有可能的。任何二进制文件中入口点的唯一魔力在于,可执行文件中的第一条指令是指向入口点函数地址的goto(jmp)。当然,在.NET中,跳转是到一个.NET存根,它在.NET运行时环境中包装程序的剩余生命周期,然后调用main(),但功能上是相同的,值得注意的是,Microsoft并没有假装OnStart和OnStop是特例,因为这必须在编译器中完成,而且是愚蠢的。:)