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

When to compose application root in a windows service

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

此类服务的应用程序根应该在服务的 OnStart 方法中组成,还是早于 static void Main 的一部分?

似乎在服务的 OnStart 方法中进行组合(并在 OnStop 方法中销毁/处置它)可能会有优势,因为重新启动服务会随后组合一个新的应用程序根目录.我在这里看到的唯一真正的缺点是,如果我使用像 Topshelf 这样的工具,我不能使用 DI 容器来获取我的服务实例 class。再一次,这可能不是一个真正的缺点。尽管如此,我阅读的大多数应用程序都是在 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;
        }
    }
}

composition.cs

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();
    }
}

imyservice.cs

public interface IMyService
{
    void Start();
    void Stop();
}

The only real disadvantage I can see here is that if I am using a tool like Topshelf, I can't use the DI container to obtain an instance of my Service class

这是真的,但您不需要访问 program.cs 代码,只需访问 MyService 代码,它将代表您服务的实际 "core" 代码。

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

像往常一样,恕我直言。 :)