c++ windows获得当前工作目录文件_使用.NET Core 3.0创建windows服务

6c93d1c0191c1c79f41e78304e703383.png

小伙伴们大家好,今儿我将和大家分享一下如何基于.net core 3.0编写windows service,以及介绍一些例如读取配置,记录日志文件,依赖注入等技术细节,在文章的最后还会介绍windows service的安装过程。具体可参照示例源码

windows服务的过去与现在

相信很多小伙伴都使用.net写过windows服务,在.NET framework时代,创建一个windows服务并不是什么难事儿,但调试起来的痛苦却是记忆犹新。后来有了Topshelf框架,很多问题都得到了好转。

后来进入.net core 2.x时代,编写windows服务又变的繁琐了起来,幸运的是,Topshelf后来也支持Core了,使得我们可以借助Console Application轻松构建服务,一切又美好了起来。

在.net core 3.0时代,我们迎来了今天的主角,worker service

通过它我们可以轻松的构建跨平台的服务,无论是windows平台的windows服务,还是Linux平台的Systemd进程。

废话不多说,我们开始吧

创建服务

  1. 打开vs2019
  2. 创建新项目
  3. 选择Woker Service,点击下一步
  4. 起一个项目名,然后点击创建

b22eb6812f896429423eba005d0d96a5.png

创建的完的目录结构如下

81e51e77c379853c84c007b67da97dde.png
目录结构

为了让worker service能够作为windows 服务运行,我们还需要安装一下NuGet包:Microsoft.Extensions.Hosting.WindowsServices,接下来我们修改一下Program.cs文件,将UseWindowsService()扩展方法添加到CreateHostBuilder中。

UseWindowsService主要做了三件事:

  1. 设置lifetime为WindowsServiceLifetime
  2. 设置content root为BaseDirectory
  3. 开启event log

添加Serilog

我们安装下面几个NuGet包:

  1. Serilog.Extensions.Hosting
  2. Serilog.Sinks.Console
  3. Serilog.Sinks.File

我们再修改一下Program.cs

public 

在上面的代码段中,我们开启了两个logging sinks,console,file。在代码段的结尾,我们向HostBuilder中添加了UseSerilog,以示意host使用serilog作为logging provider。

值得注意的是,记录文件的路径我设置为BaseDirectory,实际上UseWindowsService()这个方法内部也做了同样的事,以便于程序能够在正确的位置读取到配置文件。很多小伙伴错误的使用了Directory.GetCurrentDirectory()这个函数来指明路径,但却得不到正确的结果,原因是Directory.GetCurrentDirectory()这个方法在http://Asp.net Core中是没有问题的,但在寄宿在windows service后,当前工作目录是C:WINDOWSsystem32而不是当前程序目录,这一点需要格外关注,以免产生意想不到的错误。

编写服务

其实在worker service创建好的同时,服务也已经有个预置版本,就是项目目录中的Worker.cs。并且在ConfigureServices中通过services.AddHostedService进行了注册。项目模板很贴心的给了我们指引,不至于茫然失措。

655d3a51b1b5bcd5e76f36276b6ddba3.png

出于演示目的,我们仅简单修改Worker文件,让它实现每隔5s时间记录一次日志即可。

4742af860696ad263718a4afc06cfdc2.png

可以看出Worker这个类继承于BackgroundService,而BackgroundService又实现了IHostedService。这两个并非.net core3.0的产物,从2.x时代就已经存在了。BackgroundService有下面几个方法:

ExecuteAsync,必须实现,可在此编写后台服务逻辑

StartAsync,可重写,服务启动时会触发,在ExecuteAsync前执行

StopAsync,可重写,服务正常关闭时会触发,但如果异常终止,可能不会执行这个方法

Dispose,可重写,执行一些“清理”工作

其实StartAsync,StopAsync这两个方法都源自于IHostedService,它们会在应用程序启动和停止期间分别调用。感兴趣的小伙伴可以深入研究,这并非本文重点,这里不再赘述。

添加配置文件

我在appsettings.json中添加了一个简单的配置项,用于演示如何读取配置文件

{
  

同时创建了一个AppSettings.cs文件,用于和配置文件做映射,代码如下

    public class AppSettings
    {
        public string WorkerName { get; set; }
    }

在ConfigureServices进行绑定

ddba7e7a16995da61a1b851089844598.png

下面在改造一下worker,让它通过配置文件读取到worker的名字

e811857194c460010b8f394ca034fc6d.png

我们可以通过appsettings.{environment}.json来根据环境来分别配置

这里额外说两句,写过http://asp.net core web app的小伙伴都知道区别系统环境的是ASPNETCORE_ENVIRONMENT,但Generic Host(不知如何翻译比较恰当,姑且就叫这个)里,系统环境标识为DOTNET_ENVIRONMEN,希望小伙伴不要搞混,尤其是部署的时候,要多留意一下。

依赖注入

为了演示这块内容,我创建了IService和ServiceA。

    public interface IService
    {
        void Run();
    }
    public class ServiceA:IService
    {
        private readonly ILogger<ServiceA> _logger;

        public ServiceA(ILogger<ServiceA>logger)
        {
            _logger = logger;
        }
        public void Run()
        {
            _logger.LogInformation("Service A is running");
        }
    }

接着我们注册一下

84ddbd49cdfcf80973adaeb997cce6cd.png

这里需要注意的是,我注册的是单例,至于为什么,后面会提到。

然后改造一下Worker

7628b3b02a81bd6bde0d11cda32deb1a.png

我们运行一下看看

88109157fae1506ddfeefdc8b78d00b2.png

完美!可是,如果这么简单,就不用单独来讲了,我们换个lifetime注册试试,比如注册为Scoped

4a98998d7ae3e65b3025a99b59c8781e.png

嘿嘿,异常如期而知,我们看一下

5ae403916a2b6a9f0ccbe98361e50c7c.png

最关键的一句是,cannot consume scoped service from singleton。为什么会这样?原因是Worker生命周期是singleton,也就是单例,我们注册ServiceA的lifetime是Scoped,这就会导致回收机制在Worker之前就会将其回收,引发了DI容器的错误。

但现实场景下我们的确需要比较短周期的service(short-lived services),比如数据库连接,http client等等,这种情况怎么办呢?答案是使用IServiceProvider。下面我再改造一下Worker。

65be2cfb7ebf321592c0f3ebf0d8a830.png

一切又正确运行了

安装windows服务

一切就绪,我们先发布一下。

eeda1f38b9910051cd95ce0bae736e20.png
发布

2005669c592fb700dfd55b54eca21262.png

下面我们通过windows提供的sc进行安装,注意需要以管理员身份运行

sc create DemoService DisplayName="_Demo Service" binPath="D:MyProjectWorkerServiceDemoWorkerServiceDemobinReleasenetcoreapp3.1publishWorkerServiceDemo.exe"

905b32e1e60e4ac9f4cbe6109a729e91.png

1cbf22cd2e541beef488b8bb32d4e765.png

启动一下试试,一切正常。

696645b8685ffc9a7811bccfabfad5fa.png

如果想删除服务,我们也可以借助sc的delete来实现

00b900d32035332cbea3d14677d6b54b.png
删除服务

至此,.net core 3.0创建windows服务已经完成,写了一下午,终于写完了 。小伙伴们我们下篇文章见~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值