使用.NET Core建立Windows服务(一) - 使用官方推荐方式

原文:Creating Windows Services In .NET Core – Part 1 – The “Microsoft” Way
做者:Dotnet Core Tutorials
译者:Lamond Lu
译文:使用.NET Core建立Windows服务(一) - 使用官方推荐方式shell

建立Windows服务来运行批处理任务或者运行后台任务,是一种很是常见的模式,可是因为云服务(Amazon Lambda, Azure WebJobs以及Azure Functions)的激增,你可能不会常用Windows服务了。我的而言,我很是喜欢使用Azure WebJobs, 由于我能够直接编写一个控制台程序,而不须要考虑如何云中运行它,一个批处理文件能够将其装换成一个自动化任务,而且能够保证7*24小时的运行。c#

可是也许你尚未使用云服务,或者你有一堆要做为Windows服务运行的旧版应用程序须要转换为.NET Core, 可是不能彻底将他们转换为“无服务器”(serverless)应用。 那么这边文章就是适合你的。服务器

在许多方面,.NET Core中的Windows服务和.NET Framework中的Windows服务彻底相同。可是,在编写服务的时候,你可能会遇到一些小问题。此外,本文中,咱们仅介绍“Microsoft”方式的Windows服务建立,在后续,我会继续介绍如何使用第三方库TopShelf来简化这该过程。app

安装

因为Visual Studio没有提供建立Windows服务的模板,因此咱们须要经过建立控制台程序的方式来建立一个Windows服务。框架

建立完成以后,咱们须要安装一个Nuget程序包,这个程序包会将一些Windows特定的API添加到.NET Core中,这些API实际上已经在完整框架中提供了,可是其中许可能是Windows特有的,例如Windows服务。所以, 它们并无包含在.NET Core的基础库中,可是能够经过将Nuget程序包的方式引入到.NET Core中。
下面咱们就能够在Package Manager Console中输入如下命令。less

Install-Package Microsoft.Windows.Compatibility

代码

以上引入的Nuget程序包中,最让咱们感兴趣的是ServiceBase类。这是一个用于编写Windows服务的基类,它提供了一系列的事件钩子,包含服务启动、结束、暂停等。ide

下面呢,咱们将在代码中建立一个类,这个类负责将一些简单的日志输出到一个临时文件中。咱们将使用这个例子来了解其中的原理。咱们的代码以下:测试

class LoggingService : ServiceBase
{
    private const string _logFileLocation = @"C:\temp\servicelog.txt";
 
    private void Log(string logMessage)
    {
        Directory.CreateDirectory(Path.GetDirectoryName(_logFileLocation));
        File.AppendAllText(_logFileLocation, DateTime.UtcNow.ToString() + " : " + logMessage + Environment.NewLine);
    }
 
    protected override void OnStart(string[] args)
    {
        Log("Starting");
        base.OnStart(args);
    }
 
    protected override void OnStop()
    {
        Log("Stopping");
        base.OnStop();
    }
 
    protected override void OnPause()
    {
        Log("Pausing");
        base.OnPause();
    }
}

因此这里你会注意到,咱们的类是继承了ServiceBase类,而且咱们重写了几个事件方法,输出了一些日志。在服务启动时,会触发OnStart事件,在服务终止的时候,会触发OnStop事件。这里咱们不该该将过于繁重的任务放置在OnStart事件中来处理。debug

若是咱们想从Main方式中启动这个服务,代码很是的简单。调试

static void Main(string[] args)
{
    ServiceBase.Run(new LoggingService());
}

以上就是所有代码。

服务部署

在发布服务的时候,咱们不可能仅依靠Visual Studio来构建咱们所须要的服务,咱们还须要专门针对Windows运行时进行构建。为此,咱们须要在项目根目录的命令提示符下运行如下命令。注意,这里咱们传入了一个-r标记来告诉它要构建那个平台。

dotnet publish -r win-x64 -c Release

命令运行完毕以后,咱们能够检查如下/bin/release/netcoreappX.X/publish目录,咱们能够找到全部的发布代码,可是最重要的是,这里咱们能够获得一个可执行的exe文件。若是咱们不指定运行时,咱们只会得到一个.NET Core的dll程序集,使用这个程序集,咱们是没有办法建立Windows服务的。

如今咱们能够将这个发布目录移动带其余的任何地方,可是如今咱们就暂时使用当前的发布目录。

下一步,咱们须要使用管理员角色打开一个命令提示符,而后输入一下命令。

sc create TestService BinPath=C:\full\path\to\publish\dir\WindowsServiceExample.exe

SC命令是一个标准的Windows命令(与.NET Core无关),它能够用来安装Windows服务。这里咱们将咱们的测试服务命名为TestService,更重要的是,咱们经过BinPath参数指定了可执行exe文件。

运行以后,咱们应该会获得如下结果。

[SC] CreateService SUCCESS

而后咱们要作的就是启动服务。

sc start TestService

如今咱们能够查看一下咱们的日志文件,查看服务的运行状况。

若是想要中止并删除服务,咱们可使用一下命令。

sc stop TestService
sc delete TestService

服务调试

在这里,我真的认为,使用"Microsoft"的方式注定会失败。由于调试服务实在是太繁琐了。

首先,咱们将ServiceBase中重写的方法设置为受保护,这意味着咱们没法在类以外访问它们,这使得调试它们变得更加困难。这里我发现最好的方法是为每一个事件提供一个public方法, 并在受保护方法中调用这些public方法来完成功能,这虽然有点混乱,

public void OnStartPublic(string[] args)
{
    Log("Starting");
}
 
protected override void OnStart(string[] args)
{
    OnStartPublic(args);
    base.OnStart(args);
}

可是至少咱们能够作以下了事情了。

static void Main(string[] args)
{
    var loggingService = new LoggingService();
    if (true)   //Some check to see if we are in debug mode (Either #IF Debug etc or an app setting)
    {
        loggingService.OnStartPublic(new string[0]);
        while(true)
        {
            //Just spin wait here. 
            Thread.Sleep(1000);
        }
        //Call stop here etc. 
    }
    else
    {
        ServiceBase.Run(new LoggingService());
    }
}

你的另外一个选择是,在调试模式下进行项目发布,安装服务,而后附加调试器。实际上,这是Microsoft建议你使用的方式,可是我认为这简直一团糟。

后续

实际上,咱们能够在这里作一些其余很是有用的事情, 好比咱们能够经过建立一个install.bat批处理文件来为咱们运行SC Create命令。但我认为,上面咱们看到的调试问题,已经让我再也不想使用这种方式了。 幸运的是,有一个名为Topshelf的库能够帮助咱们减轻不少麻烦,在本系列的下一部分中,咱们将研究如何它。

相关文章
相关标签/搜索