C# 何时在windows服务中组合应用程序根目录

C# 何时在windows服务中组合应用程序根目录,c#,windows-services,topshelf,compositionroot,C#,Windows Services,Topshelf,Compositionroot,给定一个将作为windows服务运行的C#控制台应用程序,有两个应用程序入口点。第一个明显的方法是静态void Main方法。此方法的一部分工作是安装扩展了ServiceBase的东西,然后运行它以获取要调用的OnStart方法。还有更高级别的工具,如Topshelf,可以帮助您避免较低级别的ServiceBase实现,但最终还是会得到两个潜在的应用程序入口点:static void Main,以及某种OnStart方法 此类服务的应用程序根目录是否应该在服务的OnStart方法中组成,或者早于

给定一个将作为windows服务运行的C#控制台应用程序,有两个应用程序入口点。第一个明显的方法是
静态void Main
方法。此方法的一部分工作是安装扩展了
ServiceBase
的东西,然后运行它以获取要调用的
OnStart
方法。还有更高级别的工具,如Topshelf,可以帮助您避免较低级别的
ServiceBase
实现,但最终还是会得到两个潜在的应用程序入口点:
static void Main
,以及某种
OnStart
方法

此类服务的应用程序根目录是否应该在服务的
OnStart
方法中组成,或者早于作为
静态void Main
的一部分组成

似乎在服务的
OnStart
方法中组合(并在
OnStop
方法中销毁/处理)可能有好处,因为重新启动服务将组合一个新的应用程序根。我在这里看到的唯一真正的缺点是,如果我使用像Topshelf这样的工具,我就不能使用DI容器来获取我的服务类的实例。再说一次,这可能不是真正的劣势。不过,我读到的大多数应用程序都是在
Main
期间编写根目录的,而不是在
OnStart
期间编写的,我不知道为什么


一种方法真的比另一种好吗,还是取决于它,而我的问题真的是基于观点的吗?

我认为这更像是一种观点而不是事实,但我更喜欢在构建服务时编写,然后使用OnStart()激活我以前编写的服务。这是我(与Topshelf)通常的工作方式。例如:

program.cs

public class Program
{
    private static ILifetimeScope _scope;
    private static readonly ILog Log = LogManager.GetLogger(typeof(Program));

    public static void Main(string[] args)
    {
        try
        {
            XmlConfigurator.Configure();

            // configure composition
            _scope = CompositionRoot.CreateScope();

            HostFactory.Run(x =>
            {
                x.UseLog4Net();
                x.UseAutofacContainer(_scope);

                x.Service<IMyService>(svc =>
                {
                    svc.ConstructUsingAutofacContainer();
                    svc.WhenStarted(tc => tc.Start());
                    svc.WhenStopped(tc =>
                    {
                        tc.Stop();
                        _scope.Dispose();
                    });
                });

                x.RunAsNetworkService();
                x.StartManually();
            });
        }
        catch (Exception e)
        {
            Log.Error("An error occurred during service construction.", e);
            throw;
        }
    }
}
internal class CompositionRoot
{
    public static ILifetimeScope CreateScope()
    {
        var builder = new ContainerBuilder();

        builder.RegisterType<MyService>().As<IMyService>().SingleInstance();
        // other things you want to register

        return builder.Build();
    }
}
public interface IMyService
{
    void Start();
    void Stop();
}
我在这里看到的唯一真正的缺点是,如果我使用像Topshelf这样的工具,我就不能使用DI容器来获取我的服务类的实例

这是真的,但是您不需要访问program.cs代码,只需要访问MyService代码,它将代表您服务的实际“核心”代码

此外,当您停止服务时,您实际上会终止它(除非暂停它),因此该组合将再次执行,无论您是否将其放入“onStart()”中


和往常一样,伊姆霍:)

Main是唯一的进程条目,因此它更像是一个“进程范围”的构造函数。一个服务程序/流程可以承载多个服务实例,而不仅仅是一个实例。每个服务实例构造函数在每个进程生命周期中只应调用一次,但可以重复调用OnStart/OnStop。现在,我真的不明白应用程序根是什么意思,也不明白您想要编写什么,但我认为您应该将每个服务初始化与实例初始化联系起来。所以,如果您使用ServiceBase,它应该以某种方式与它的构造函数相关联。两种情况下的入口点都是Main()。发生的唯一额外的事情是服务管理器的OnStart()调用,您通常启动一个线程来做一些有用的事情。延迟任何事情都没有意义,它不会优化任何东西,在Main()开始运行后,OnStart()调用会很快发生。@HansPassant那么当windows服务重新启动时,Main()方法会再次被调用吗?如果是这样的话,那么我误解了什么,你是对的,这个问题无关紧要。