【问题标题】:Run windows service automatically forever, after starting manually for the first time第一次手动启动后,永远自动运行windows服务
【发布时间】:2016-05-16 19:55:40
【问题描述】:

我创建了一个 Windows 服务应用程序。它根据 app.config 文件中包含的应用程序设置运行。它将同时安装在不同的位置(网络、PC)。每个位置都需要在 app.config 文件中设置自己的参数。所以我不希望它在安装后自动运行。通过这样做,每个位置用户都可以打开配置文件并对其进行更改。然后他们可以启动服务。但在那之后,该服务将永远运行。即使他们重新启动Windows,它也会在Windows打开后自动运行。

这是我的安装程序类。安装后不会自动运行。那挺好的。但是如果我手动运行它并重新启动PC,当重新启动完成时,它仍然等待手动启动。我该怎么办?

public partial class MyServiceInstaller : System.Configuration.Install.Installer
{
    ServiceInstaller _serviceInstaller = new ServiceInstaller();
    ServiceProcessInstaller _processInstaller = new ServiceProcessInstaller();
    string _serviceName = "MyService";
    string _displayName = "My Service";
    string _description = "My Service - Windows Service";

    public MyServiceInstaller()
    {
        InitializeComponent();

        this.BeforeInstall += new InstallEventHandler(MyServiceInstaller_BeforeInstall);

        _processInstaller.Account = ServiceAccount.LocalSystem;

        _serviceInstaller.StartType = ServiceStartMode.Automatic;
        _serviceInstaller.Description = _description;
        _serviceInstaller.ServiceName = _serviceName;
        _serviceInstaller.DisplayName = _displayName;

        Installers.Add(_serviceInstaller);
        Installers.Add(_processInstaller);
    }

    protected override void OnCommitted(System.Collections.IDictionary savedState)
    {
        ServiceController sc = new ServiceController(_serviceName);

        if (sc.Status != ServiceControllerStatus.Running)
        {
            TimeSpan timeout = TimeSpan.FromMilliseconds(10000);
            sc.Start();
            sc.WaitForStatus(ServiceControllerStatus.Running, timeout);
            sc.Stop();
        }
        else
        {
            RestartService(10000);
        }
    }

    private void RestartService(int timeoutMiliseconds)
    {
        ServiceController service = new ServiceController(_serviceName);

        int millisec1 = Environment.TickCount;
        TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMiliseconds);

        service.Stop();
        service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);

        int millisec2 = Environment.TickCount;
        timeout = TimeSpan.FromMilliseconds(timeoutMiliseconds - (millisec2 - millisec1));

        service.Start();
        service.WaitForStatus(ServiceControllerStatus.Running, timeout);
    }

    void MyServiceInstaller_BeforeInstall(object sender, System.Configuration.Install.InstallEventArgs e)
    {
        List<ServiceController> services = new List<ServiceController>(ServiceController.GetServices());

        foreach (ServiceController s in services)
        {
            if (s.ServiceName == this._serviceInstaller.ServiceName)
            {
                ServiceInstaller ServiceInstallerObj = new ServiceInstaller();
                ServiceInstallerObj.Context = new System.Configuration.Install.InstallContext();
                ServiceInstallerObj.Context = Context;
                ServiceInstallerObj.ServiceName = _serviceName;
                ServiceInstallerObj.Uninstall(null);
            }
        }
    }
}

【问题讨论】:

  • 您的代码似乎将启动类型设置为自动。您能否检查事件日志以查看您的服务是否正在尝试自动启动,但失败了。如果您的服务依赖于另一个尚未启动的服务,就会发生这种情况。
  • @sgmoore 感谢您的评论。我意识到我的代码依赖于其他一些代码,这些代码需要等待一段时间才能在重新启动后执行。请写下这个作为答案,我会标记它。

标签: c# windows-services


【解决方案1】:

您可以通过下载名为 TopShelf 的 NuGet 包来简化此操作。

简单总结一下,引用他们的page

Topshelf 是一个使用 .NET 编写的托管服务框架 框架。服务的创建被简化,允许开发人员 创建一个简单的控制台应用程序,可以安装为 使用 Topshelf 服务。原因很简单:远 调试控制台应用程序比调试服务更容易。而一旦 应用程序经过测试并准备好投入生产,Topshelf 让一切变得简单 将应用程序安装为服务。

【讨论】:

    【解决方案2】:

    您的代码似乎已经将启动类型设置为自动。

    您能否检查事件日志以查看您的服务是否尝试自动启动,但失败了。如果您的服务依赖于另一个尚未启动的服务,则可能会发生这种情况。

    【讨论】:

    • 谢谢,由于依赖关系而失败。它应该在重新启动后等待一段时间才能成功执行。因此,将安装程序的 DelayedAutoStart 值设置为 true 即可解决问题。
    【解决方案3】:

    你可以在服务启动后使用sc config修改启动类型。

    例如。

    sc config yourservicename start=auto
    

    或者你可以使用ChangeServiceConfig

    【讨论】:

    • 谢谢,但安装完成后它的启动类型似乎已经是自动。所以,没必要改。此外,用户永远不会运行任何 cmd 命令。
    • @OrkunBekar 如果启动类型是自动的,那么在 Windows 重新启动后服务必须启动,但可能由于某种原因它失败了,请查看 EventLog 中的服务错误。
    • @orkunbekar 如果启动类型设置为自动,它将在重新启动时自动启动。但是将启动类型设置为自动并不意味着“立即启动”。您必须手动进行初始启动。此外,这并不意味着“停止/崩溃后重新启动”,对此有单独的设置。
    • @BWA 我查看了活动,但找不到有用的信息,谢谢。
    • @derpirscher 感谢您提供这些信息。然后我必须在 oncommitted 中编写一个算法以在第一次停止,然后在第二次运行后它不会再次调用 sc.stop。对吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多