dotnet core TopShelf Windows 服务启动失败

dotnet core TopShelf Windows Service fails to start

我有一个 dotnet 核心控制台应用程序构建来连接到 Sql Service Broker 实例以监视 table 更改。

该应用程序监控一个 table 从 ERP 系统更新,然后将消息发布到我们的总线。

当 运行作为控制台应用程序或在我的 IDE 中调试时 运行 没问题。

我在使用 TopShelf 将其配置为 windows 服务时遇到问题。

这里是入口点:

        private static void Main(string[] args)
       {
        RegisterComponents();

        var serviceHost = HostFactory.Run(sc =>
        {
            sc.Service<ISalesOrderMonitorService>(s =>
            {
                var sqlListener = _container.ResolveNamed<SqlDependencyEx>(ListenerKey.SalesOrder);
                var changeHandler = _container.Resolve<ISalesOrderChangeHandler>();
                var listenerConfig = _container.ResolveNamed<ListenerConfiguration>(ListenerKey.SalesOrder);
                var logger = _container.Resolve<ILogger<SalesOrder>>();

                s.ConstructUsing(f =>
                    new SalesOrderMonitorService(sqlListener, changeHandler, listenerConfig, logger));

                s.WhenStarted(tc => tc.Start());
                s.WhenStopped(tc => tc.Stop());
            });
        });

        var exitCode = (int) Convert.ChangeType(serviceHost, serviceHost.GetType());

        Environment.ExitCode = exitCode;
    }

"worker" class:

    public abstract class ServiceBase<T, TZ> : IService<T>
    where T : IChangeHandler
{
    protected readonly IChangeHandler ChangeHandler;
    protected readonly SqlDependencyEx Listener;
    protected readonly ListenerConfiguration ListenerConfiguration;
    protected readonly ILogger<TZ> Logger;

    protected ServiceBase(SqlDependencyEx listener, IChangeHandler changeHandler,
        ListenerConfiguration listenerConfiguration, ILogger<TZ> logger)
    {
        Logger = logger;
        ListenerConfiguration = listenerConfiguration;
        Listener = listener;
        ChangeHandler = changeHandler;
    }

    public virtual void Start()
    {
        try
        {
            Listener.TableChanged += (o, e) => ChangeHandler.Process(e);

            Listener.Start();

            Logger.LogDebug(
                $"Listening to changes on the {ListenerConfiguration.Table} table in the {ListenerConfiguration.Database} database");
        }
        catch (Exception e)
        {
            Logger.LogError(e, e.Message);
            throw;
        }

    }

    public virtual void Stop()
    {
        Listener.Stop();
    }

通过TopShelf安装没问题:

c:>{ServiceName}.exe install -username "serviceAccount" -password "superSecret" -servicename "ServiceName" -servicedescription "Description" -displayname "Service DisplayName" --autostart

当我开始服务时 - 我得到这个:

这是误导,因为事件查看器显示:

这比 30 秒更快。这肯定与我如何配置 TopShelf 有关。

如前所述 - 该应用程序在 运行 "debug" 或什至只是一个 exe 控制台时工作正常。

我明白了。实际上,来自@DotNetPadawan 和@Lex Li 的评论都间接地把我带到了那里。

对于初学者 - 启用远程调试器让我明白我的 appsetting.json 没有被读入我的 IConfiguration。这真的很令人困惑,因为一切都很好 运行 在本地使用调试器甚至只是启动 exe。

Lex Li 指出的 link 没有提供答案 - 但是那篇文章有这个参考:

Host and Deploy aspnetcore as a Windows Service

我就是在这里发现了这个小金块:

The current working directory returned by calling GetCurrentDirectory for a Windows Service is the C:\WINDOWS\system32 folder. The system32 folder isn't a suitable location to store a service's files (for example, settings files). Use one of the following approaches to maintain and access a service's assets and settings files.

link 解释了如果应用 运行 作为服务,如何有条件地设置当前目录。

        var isConsole = args.Contains("-mode:console");

        if (!isConsole)
        {
            var pathToExe = Process.GetCurrentProcess().MainModule?.FileName;
            var pathToContentRoot = Path.GetDirectoryName(pathToExe);
            Directory.SetCurrentDirectory(pathToContentRoot);
        }

为遇到此问题的任何其他人发布此信息。

无可否认 - netcore 3.0 可能是更好的选择 - 但我没有足够的带宽将此存储库(很多共享的东西)升级到 3.0。我需要让它工作。