检测/侦听服务启动和停止状态的更改



我有一个C#应用程序,它使用的Windows服务并不总是打开的,我希望能够在服务启动和关闭时发送电子邮件通知。我已经写好了电子邮件脚本,但我似乎不知道如何检测服务状态的变化。

我一直在阅读ServiceController类,我认为WaitForStatus()方法可能是我所需要的,但我还没有找到一个在尚未启动的服务上使用它的示例EDIT:由于WaitForStatus()方法繁忙等待,我需要在侦听服务启动/停止时执行服务运行的其余程序,我不认为这是适合我的方法,除非有人有一个将此方法与多线程相结合的干净高效的解决方案。

 

更多:

  • 该服务将不会由应用程序启动-应用程序用户将直接从"管理工具"中的"服务"窗口启动该服务
  • 所使用的服务不是默认的Windows服务,而是为与此应用程序一起使用而设计的自定义服务

 

谢谢你的帮助!

 

附言:请注意,我是C#的新手,在这里学习。

 

更新:

我已经设法在每次服务启动时发送警报电子邮件:当我继续阅读我的代码(不幸的是,我无法在这里发布)时,我注意到用于创建服务的类正在扩展ServiceBase类,并且有人制作了一个自定义OnStart()方法来覆盖默认方法。我向新的OnStart()方法添加了必要的方法调用,它成功地发送了通知。

我试图对OnStop()方法做同样的事情,但对我来说效果不太好——在继续之前,我想补充一点,我已经用Java编程好几年了,我非常熟悉Java设计模式。

我试图用一个调用电子邮件通知的方法覆盖ServiceBase类的OnStop()方法,这在Java中是可行的,将MyService强制转换为ServiceBase类型,然后重新调用ServiceBase类的Stop()方法(注意:OnStop()是受保护的方法,因此不能直接调用它-Stop()方法调用OnStop(),然后继续执行必要的代码以停止服务)。我认为转换为类型ServiceBase会强制调用默认的OnStop()方法,而不是我的自定义方法。

正如你所想象的,在我设法迫使我的电脑硬关机之前,我的收件箱里成功发送了不到10000封电子邮件。

我现在需要的是一种方法,要么使用我重写的OnStop()方法,然后让它调用默认方法,要么用另一种方法来解决这个问题。我们非常感谢所有的帮助。非常感谢。

 

对于那些使用多线程解决方案的人:

protected override void OnStart(string[] args) {
     string subject = "Notice: Service Started";
     string body = "This message is to notify you that the service " +
         "has been started. This message was generated automatically.";
     EmailNotification em = new EmailNotification(subject, body);
     em.SendNotification();
     ...INITIALIZE LISTENER FOR SERVICE STOPPING HERE...
     ...custom stuff to be run on start...
 }

另外,请记住,在中调用此方法的类,让我们称之为Service,扩展了ServiceBase类。

 

更新二:

关于我使用NotifyServerStatusChange的建议,我了解到由于各种原因,解决方案不允许使用系统功能。需要澄清的是,只有完全在C#和.NET范围内的解决方案才是可行的。再次感谢您的帮助!

以下是解决方案以及我以前找不到它的原因:正如我前面所说,我的类扩展了ServiceBase类。在我的第一次更新中,我发布了我试图用与Java相同的方法来解决这个问题:通过强制转换。然而,在C#中,如果在派生类中重写基方法,那么强制转换显然不允许调用它。当我第一次发布这个问题和这个更新时,我不知道的一件事(显然也是没有人想到的一件事情)是C#包含了base构造函数,该构造函数可用于从派生类调用基类的方法。由于base构造函数可用于C#中的任何类,因此它不会出现在ServiceBase class文档中。

一旦我学会了这一点,我就可以采用我的原始解决方案,并将其修改为使用基类:

    protected override void OnStop() {
        string subject = "Notice: Service Stopped";
        string body = "This message is to notify you that the service has " +
            "been stopped. This message was generated automatically.";
        EmailNotification em = new EmailNotification(subject, body);
        em.SendNotification();
        base.OnStop();
    }

当我在Visual Studio中玩代码时,我发现了这一点,并在我的IntelliSense中注意到了base。我点击转到它的定义,它把我送到ServiceBase(在那里它显然没有定义)。注意到我的代码中没有定义base,它是ServiceBase类的一个实例后,我意识到它一定是某种构造函数。在谷歌上快速搜索后,我找到了我要找的东西。IntelliSense的发展之路!

感谢大家的帮助!

如果您想要一个没有win32 api的.NET解决方案,请查看下面的解决方案。我从ServiceController类继承,并在Task内部使用WaitForStatus()使其不阻塞,然后在状态更改时引发事件。也许它需要更多的测试,但对我有效:

类别定义

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.ServiceProcess; // not referenced by default
public class ExtendedServiceController: ServiceController
{
    public event EventHandler<ServiceStatusEventArgs> StatusChanged;
    private Dictionary<ServiceControllerStatus, Task> _tasks = new Dictionary<ServiceControllerStatus, Task>();
    new public ServiceControllerStatus Status
    {
        get
        {
            base.Refresh();
            return base.Status;
        }
    }
    public ExtendedServiceController(string ServiceName): base(ServiceName)
    {
        foreach (ServiceControllerStatus status in Enum.GetValues(typeof(ServiceControllerStatus)))
        {
            _tasks.Add(status, null);
        }
        StartListening();
    }
    private void StartListening()
    {
        foreach (ServiceControllerStatus status in Enum.GetValues(typeof(ServiceControllerStatus)))
        {
            if (this.Status != status && (_tasks[status] == null || _tasks[status].IsCompleted))
            {
                _tasks[status] = Task.Run(() =>
                {
                    try
                    {
                        base.WaitForStatus(status);
                        OnStatusChanged(new ServiceStatusEventArgs(status));
                        StartListening();
                    }
                    catch
                    {
                        // You can either raise another event here with the exception or ignore it since it most likely means the service was uninstalled/lost communication
                    }
                });
            }
        }
    }
    protected virtual void OnStatusChanged(ServiceStatusEventArgs e)
    {
        EventHandler<ServiceStatusEventArgs> handler = StatusChanged;
        handler?.Invoke(this, e);
    }
}
public class ServiceStatusEventArgs : EventArgs
{
    public ServiceControllerStatus Status { get; private set; }
    public ServiceStatusEventArgs(ServiceControllerStatus Status)
    {
        this.Status = Status;
    }
}

用法

static void Main(string[] args)
{
    ExtendedServiceController xServiceController = new ExtendedServiceController("myService");
    xServiceController.StatusChanged += xServiceController_StatusChanged;
    Console.Read();
    // Added bonus since the class inherits from ServiceController, you can use it to control the service as well.
}
// This event handler will catch service status changes externally as well
private static void xServiceController_StatusChanged(object sender, ServiceStatusEventArgs e)
{
    Console.WriteLine("Status Changed: " + e.Status);
}

ServiceController类有一个WaitForStatus方法。不过,它在内部进行民意调查。

如果不能PInvoke NotifyServiceStatusChange,则必须轮询该服务。例如:

ServiceController sc = new ServiceController("Some Service");
Console.WriteLine("Status = " + sc.Status);

您可以使用wmi监视事件:technet.microsoft.com/en-us/library/ff730927.aspx

请非常小心地使用NotifyServiceStatusChange(),因为它仅在Windows Vista/Windows 2008(及更高版本)上受支持。如果您针对以下任何平台,则不能使用该API。(仍然有很多XP/Windows 2000-2003系统。)

更糟糕的是,在服务重新启动的情况下,轮询并不总是可靠的,因为如果您在速度非常快的系统(SSD驱动器或虚拟机上的预缓冲I/O)上轮询服务,该服务可能会在两次轮询之间重新启动。

相关内容

  • 没有找到相关文章

最新更新