【问题标题】:dotnet core TopShelf Windows Service fails to startdotnet core TopShelf Windows 服务无法启动
【发布时间】:2019-09-24 18:50:40
【问题描述】:

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

该应用监控一个从 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;
    }

“工人”阶级:

    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 有关。

如前所述 - 应用程序在运行“调试”或仅作为 exe 控制台时运行良好。

【问题讨论】:

标签: .net-core topshelf


【解决方案1】:

我明白了。实际上,@DotNetPadawan 和 @Lex Li 的两个 cmets 都间接地让我到达了那里。

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

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

Host and Deploy aspnetcore as a Windows Service

我就是在这里找到了这个小金块:

为 Windows 服务调用 GetCurrentDirectory 返回的当前工作目录是 C:\WINDOWS\system32 文件夹。 system32 文件夹不是存储服务文件(例如,设置文件)的合适位置。使用以下方法之一来维护和访问服务的资产和设置文件。

该链接说明了如果应用程序作为服务运行,如何有条件地设置当前目录。

        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 可能是更好的选择——但我没有足够的带宽将这个 repo(很多共享的东西)升级到 3.0。我需要让这个工作。

【讨论】:

  • 这正是我遇到的问题,非常感谢分享这个!
  • 深入研究一下。另一种不需要您传递任何参数的方法是调用 WindowsServiceHelpers.IsWindowsService ,然后仅在您作为服务运行时强制当前目录。这里的例子 - gist.github.com/scheffler/012516cdba44b508df366f3637a1c0c5
猜你喜欢
  • 1970-01-01
  • 2020-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多