.net core dotnet core TopShelf Windows服务无法启动

.net core dotnet core TopShelf Windows服务无法启动,.net-core,topshelf,.net Core,Topshelf,我有一个dotnetcore控制台应用程序构建,用于连接到sqlservicebroker实例以监视表更改 该应用程序监视一个从ERP系统更新的表,然后将消息发布到我们的总线 它在作为控制台应用程序运行或在IDE中调试时运行良好 我在使用TopShelf将其配置为windows服务时遇到问题 以下是切入点: private static void Main(string[] args) { RegisterComponents();

我有一个dotnetcore控制台应用程序构建,用于连接到sqlservicebroker实例以监视表更改

该应用程序监视一个从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;
    }
当我开始服务时,我得到以下信息:

这具有误导性,因为事件查看器显示以下内容:

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


如上所述-应用程序在运行“调试”或甚至作为exe控制台时工作正常

我弄明白了。事实上,@DotNetPadawan和@lexli的评论间接地让我达到了目的

首先,启用远程调试器会让我觉得appsetting.json没有读入我的IConfiguration。这真的很让人困惑,因为在本地使用调试器运行,甚至只是启动exe,一切都可以正常工作

Lex Li指出的链接没有提供答案,但该条提到:

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

通过调用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可能是更好的方式,但我没有足够的带宽将所有东西都升级到3.0。我需要让它工作起来

您可以尝试从代码显式启动调试器,以便逐步解决问题。尝试将此行
System.Diagnostics.Debugger.Launch()
添加到Main()方法的开头。从昨天开始查看此答案以了解详细信息,.NET Core 3.0的内置支持是您应该采取的方式,这正是我遇到的问题,非常感谢您的分享!再深入一点。另一种不需要传入任何参数的方法是调用WindowsServiceHelpers.IsWindowsService,然后仅在作为服务运行时强制当前目录。这里的例子-
c:>{ServiceName}.exe install -username "serviceAccount" -password "superSecret" -servicename "ServiceName" -servicedescription "Description" -displayname "Service DisplayName" --autostart
        var isConsole = args.Contains("-mode:console");

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