Windows服务使用Console模式运行
Windows服务定义
Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。
这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。
这种服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上工作的其他用户,需要长时间运行功能时使用。
还可以在不同于登录用户的特定用户帐户或默认计算机帐户的安全上下文中运行服务。
我们在开发一些无UI服务或者Job的时候,一般我们会选择Windows服务来开发。
一般开发者对Windows服务的感觉是很复杂的,因为它出了问题不好调试,难以定位bug的root cause。
所以本文主要讲解:
如何使用Console的运行方式来执行Windows服务?
这样运行的好处有很多,对开发人员友好,方便开发人员调试程序,更加容易发现程序里面的错误,以及更加容易的定位bug的root cause。
实现思路如下:
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
bool isRunByConsoleMode = true;
ServiceBase[] servicesToRun;
servicesToRun = new ServiceBase[]
{
new MyService()
};
if (isRunByConsoleMode)
{
RunConsoleMode(servicesToRun);
}
else
{
ServiceBase.Run(servicesToRun);
}
}
通过isRunByConsoleMode来控制是否使用Console的运行方式来执行Windows服务。
上面的代码isRunByConsoleMode是hard code的,实际项目中我们可以把这个值写在配置文件中或者数据库中等等。
RunConsoleMode的方法实现如下:
static void RunConsoleMode(ServiceBase[] servicesToRun)
{
Console.WriteLine("Services running in console mode.");
MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart",
BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.WriteLine("{1} Starting {0}...", service.ServiceName, DateTime.Now);
onStartMethod.Invoke(service, new object[] { new string[] { } });
Console.WriteLine("Started");
}
Console.WriteLine("Press any key to stop the services and end the process...");
Console.ReadLine();
MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop",
BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.WriteLine("Stopping {0}...", service.ServiceName);
onStopMethod.Invoke(service, null);
Console.WriteLine("Stopped");
}
Console.WriteLine("All services stopped.");
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
因为这个方法中使用了Console类,所以我们在创建项目的类型必须是Console Application,如果是Windows application,程序虽然不会出错,但是不会弹出Console程序的窗口,开发人员无法友好调试程序。
所以我们如果想使用Console的运行方式调用Windows服务,Windows服务所在项目,它的类型必须是Console Application。
所以我们首先新建一个Console项目,然后在里面添加一个Windows服务,定义如下:
public partial class MyService : ServiceBase
{
FileInfo fileInfo;
public MyService()
{
InitializeComponent();
fileInfo = new FileInfo(@"C:\Temp\MyService.txt");
}
protected override void OnStart(string[] args)
{
using (StreamWriter streamWriter = fileInfo.AppendText())
{
streamWriter.WriteLine("Start MyService!");
}
}
protected override void OnStop()
{
using (StreamWriter streamWriter = fileInfo.AppendText())
{
streamWriter.WriteLine("Stop MyService!");
}
}
}
这个服务主要用来证明我们的demo,所以逻辑尽量简单,在服务开始和停止的时候,往文件里面写log。
代码写好之后,我们可以正常运行。