我有一个C#应用程序,它使用的Windows服务并不总是打开,我希望能够在服务启动和关闭时发送电子邮件通知。我编写了电子邮件脚本,但我似乎无法弄清楚如何检测服务状态的变化。
我一直在阅读编辑:由于ServiceController
课程,我认为WaitForStatus()
方法可能就是我需要的方法,但我无法找到一个例子。用于尚未启动的服务。WaitForStatus()
方法忙等待,我需要执行服务运行的其余程序,同时监听服务启动/停止,我不认为这是我的方法,除非有人有一个解决方案,使用这种方法结合多线程,并且干净,高效。
更多:
感谢您的帮助!
P.S。请注意,我是C#的新手,在我去的时候正在学习。
更新:
我设法在每次服务启动时收到警报电子邮件:当我继续阅读我所拥有的代码时(遗憾的是,我不能在这里发布),我注意到用于创建service正在扩展ServiceBase
类,并且有人创建了一个自定义OnStart()
方法来覆盖默认方法。我向新的OnStart()
方法添加了必要的方法调用,并成功发送了通知。
我试图对OnStop()
方法做同样的事情,但这对我来说效果不好 - 在继续之前,我想补充说我已经用Java编程了好几年了,我非常熟悉Java设计模式。
我试图在Java中使用的方法是使用调用电子邮件通知的方法覆盖ServiceBase
类的OnStop()
方法,将MyService
强制转换为{ {1}}然后重新调用ServiceBase
类的ServiceBase
方法(注意:Stop()
是受保护的方法,因此无法直接调用 - OnStop()
方法调用Stop()
然后继续使用必要的代码来停止服务)。我认为转换为OnStop()
类型会强制调用默认的ServiceBase
方法,而不是我的自定义方法。
正如您可能想象的那样,在我成功将计算机强行关机之前,我最终只有不到10,000封电子邮件成功发送到我的收件箱。
我现在需要的是使用我重写的OnStop()
方法,然后让它调用默认方法或另一种解决此问题的方法。任何和所有的帮助非常感谢。非常感谢。
对于那些有多种解决方案的人:
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
的建议,我了解到由于各种原因,解决方案不允许使用系统功能。为了澄清,只有纯粹属于C#和.NET范围的解决方案才是可行的。再次感谢您的帮助!
答案 0 :(得分:3)
以下是解决方案以及我之前找不到的原因:正如我之前所说,我的类扩展了ServiceBase类。在我的第一次更新中,我发布了我尝试解决这个问题,就像我用Java解决它一样:通过强制转换。但是,在C#中,如果在派生类中覆盖它,显然不允许调用基本方法。当我第一次发布这个问题时,我不知道的事情之一和这个更新(显然是其中一个没有人想到的事情)是C#包含可用于调用方法的base
构造函数派生类的基类。由于base
构造函数可用于C#中的任何类,因此它不会出现在ServiceBase Class documentation中。
一旦我学会了这个,我就可以使用我原来的解决方案并修改它以使用基类:
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类的一个实例后,我意识到它一定是某种构造函数。快速谷歌搜索后,我找到了我想要的东西。走智能感!
感谢大家的帮助!
答案 1 :(得分:1)
ServiceController类有WaitForStatus
方法。但是在内部它会进行轮询。
答案 2 :(得分:1)
您可以使用wmi监控事件:technet.microsoft.com/en-us/library/ff730927.aspx
答案 3 :(得分:1)
如果你不能PInvoke NotifyServiceStatusChange,那么你将不得不轮询该服务。例如:
ServiceController sc = new ServiceController("Some Service");
Console.WriteLine("Status = " + sc.Status);
答案 4 :(得分:0)
使用NotifyServiceStatusChange()非常小心,因为它仅在Windows Vista / Windows 2008(及更高版本)上受支持。如果您定位到以下任何平台,则无法使用该API。 (那里还有很多XP / Windows 2000-2003系统。)
更糟糕的是,在服务重新启动的情况下,轮询并不总是可靠的,因为如果您在非常快的系统上轮询服务(SSD驱动器或虚拟机上的预缓存I / O),服务可能会在两次民意调查之间重启。
答案 5 :(得分:0)
如果您想要一个没有 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);
}