当我从服务窗口C#中选择停止时,Windows服务不会停止

时间:2015-10-14 09:14:55

标签: c# windows-services backgroundworker

我已经编写了一个Windows服务,但是当我尝试停止服务时,它表示此时服务无法停止。这是我的全班:

public partial class RenewalsService : ServiceBase
{
    private readonly ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
    private Thread _thread;

    public RenewalsService()
    {
        InitializeComponent();
        this.CanStop = true; 
    }

    protected override void OnStart(string[] args)
    {
        _thread = new Thread(WorkerThread)
        {
            Name = "Renewals Service Thread",
            IsBackground = true
        };
        _thread.Start();
    }

    protected override void OnStop()
    {
        try
        {

            if (!_shutdownEvent.SafeWaitHandle.IsClosed)
            {
                _shutdownEvent.Set();
            }
            if (_thread.IsAlive)
            {
                if (!_thread.Join(3000))
                {
                    // give the thread 3 seconds to stop
                    _thread.Abort();
                }
            }
        }
        catch (Exception ex)
        {
            // _thread.Join may raise an error at this point. If it does we dont care. We dont care about any other exceptions
            // since we are already in the process of closing the service.

        }
        finally
        {
            IError logger = new Logger();
            Exception ex = new Exception("The Renewals service has been stopped.");
            logger.Log(this, SeverityEnum.Warning, ex);
            Environment.ExitCode = 0;
            Environment.Exit(Environment.ExitCode);
        }
    }


    private void WorkerThread()
    {
        try
        {
            while (!_shutdownEvent.WaitOne(1))
            {

                string timeToRun = ConfigurationManager.AppSettings["RunTime"];
                string[] timeStrings = timeToRun.Split(':');
                TimeSpan runtime = new TimeSpan(0, Int32.Parse(timeStrings[0]), Int32.Parse(timeStrings[1]), Int32.Parse(timeStrings[2]));

                if (DateTime.Today.TimeOfDay.Hours == runtime.Hours &&
                    DateTime.Today.TimeOfDay.Minutes == runtime.Minutes)
                {
                    Renewals renewals = new Renewals();
                    renewals.GenerateRenewal();

                }
            }
        }
        catch (Exception ex)
        {
            IError logger = new Logger();
            logger.Log(this, SeverityEnum.Warning, ex);
            this.OnStop();

        }

    }
}

确保用户可以停止服务缺少什么。

2 个答案:

答案 0 :(得分:0)

您的代码对我来说没问题,所以这里有几件事需要检查。

首先,GenerateRenewal()方法需要很长时间才能完成吗?如果是这样,您可能需要定期检查该方法中的_shutdownEvent以便及时关闭。当然,您已将该主题标记为后台主题,因此当您告诉服务停止时, 应该 关闭。我还没有看到后台线程阻止进程终止,但我想总有那种机会。

其次,对我来说更可能的罪魁祸首是该服务已因异常而关闭。当服务关闭时,服务控制台不会自动刷新,因此您可以在不应该看到停止链接的情况下看到它。如果按F5,控制台将刷新,如果您的服务已停止,则Start链接应该是唯一可用的。检查日志文件以查看是否已触发异常处理程序。

更新

所以看起来你的WorkerThread()方法抛出异常,导致服务停止。这解释了为什么Stop链接在您单击时会显示错误消息。

如果您拥有足够的权限,请使用此link调试您的服务,以找出发生异常的原因。

HTH

答案 1 :(得分:0)

当Windows服务控制管理器(“SCM”)向服务发送“停止”命令时,基类ServiceBase类会调用重写的虚方法OnStop()。在方法的实现中,你应该做任何必要的事情来使你的服务停止状态,然后从方法返回到ServiceBase类,它处理与SCM的交互,在这种情况下告诉您的服务现已停止的SCM。 SCM将决定何时终止您的服务进程,ServiceBase类处理该问题而无需您做任何明确的事情。

对于行为良好的服务,您应该在OnStop方法结束时返回,或者抛出异常。 ServiceBase类将适当地处理事情,包括在Windows事件日志中记录异常(如果已抛出异常)。如果您的方法可能需要一段时间才能停止服务,您应该在适当的位置调用base.RequestAdditionalTime(),这样基类可以告诉SCM您还没有挂起,您的服务正在停止

我认为你的主要问题在于以下几点:

Environment.ExitCode = 0;
Environment.Exit(Environment.ExitCode);

你永远不会回到基类...所以ServiceBase类永远不会有机会对SCM做出优雅的回应......你只是单方面终止托管服务的过程。这不是一个表现良好的Windows服务。

ServiceBase类旨在支持在单个服务进程中托管的多个服务。各个服务不应该关注主机服务进程的生命周期,只关注自己服务的逻辑状态。