1. 程式人生 > 實用技巧 >C# Topshelf 或者WorkerServices搭建 Windows 服務

C# Topshelf 或者WorkerServices搭建 Windows 服務

Topshelf

Topshelf是一個用來部署基於.NET Framework 開發的服務的框架。簡化服務創建於部署過程,並且支援控制檯應用程式部署為服務。本文基於 .net core 控制檯應用程式部署為服務(.net Framework 可用)。

第一步:建立名為 TopshelfDemo 的控制檯應用程式。

第二步:通過 Nuget 安裝 Topshelf 包。

第三步:Toshelf 配置,程式碼並不多下面都有註釋。

using System;
using Topshelf;

namespace TopshelfDemo
{
    class Program
    {
        
static void Main(string[] args) { try { // 配置和執行宿主服務 HostFactory.Run(x => //1 { x.Service<Service>(s => //2 {
// 指定服務型別。這裡設定為 Service s.ConstructUsing(name => new Service()); //3 // 當服務啟動後執行什麼 s.WhenStarted(tc => tc.Start()); //4 // 當服務停止後執行什麼 s.WhenStopped(tc => tc.Stop()); //
5 }); // 服務用本地系統賬號來執行 x.RunAsLocalSystem(); //6 // 服務描述資訊 x.SetDescription("我的專案服務"); //7 // 服務顯示名稱 x.SetDisplayName("MyProjectServiceShowName"); //8 // 服務名稱 x.SetServiceName("MyProjectService"); //9 }); } catch (Exception ex) { Console.WriteLine(ex); } } } public class Service { public void Start() { //To do something } public void Stop() { //To do something } } }

第四步:安裝服務

  確保專案正常生成,然後通過管理員許可權開啟 cmd 命令視窗,找到專案所在的Debug 目錄,輸入命令:TopshelfDemo.exe install。

  如果是使用 .net core 的小夥伴你會發現 Debug下壓根沒有TopshelfDemo.exe ,這不是扯淡呢麼,別急往下看。

  由於 .net core 依賴 runtimes 所以我們需要釋出以下程式,並且選擇獨立專案就ok啦。

這時你在布後的路徑下就可以找到TopshelfDemo.exe 啦。

這時服務就安裝完畢了,我們可以通過 Windows 服務中檢視。

刪除服務命令:TopshelfDemo.exe uninstall

也可以通過sc deleteMyProjectService進行刪除

Worker Service

ASP.NET Core 3增加了一個非常有意思的功能Worker Service.他是一個ASP.NET Core模板,他允許我們建立託管長期的執行的後臺服務,這些服務具體實現IHostedService介面的後臺任務邏輯,他被成為"託管服務".同時他們可以部署到windows中Windows服務,以及Linux守護程式.

建立一個託管服務

您需要在您的環境中安裝Visual Studio 2019和.NET Core 3.0。

首先,您需要建立一個新專案,並選擇下圖所示的工作流程模板:

Program.cs:

 public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                });
    }

Worker:

BackgroundService是實現了IHostedService的基類.呼叫ExecuteAsync(CancellationToken)來執行後臺服務。實現返回一個Task,其表示後臺服務整個生存期.在ExeuteAsync(例如通過呼叫await)之前,不會啟動任何其他服務.避免在ExecuteAsync中執行長時間的阻塞初始化.StopAsync(CancellationToekn)中的主機塊等待完成ExecuteAsync

呼叫 IHostedService.StopAsync 時,將觸發取消令牌。 當激發取消令牌以便正常關閉服務時,ExecuteAsync 的實現應立即完成。 否則,服務將在關閉超時後不正常關閉。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace WorkerServiceDemo
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        public override async Task StartAsync(CancellationToken cancellationToken)
        {
            await base.StartAsync(cancellationToken);
        }

        public override async Task StopAsync(CancellationToken cancellationToken)
        {
            await base.StopAsync(cancellationToken);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }

        public override void Dispose()
        {
        }
    }
}

已使用AddHostedService擴充套件方法在IHostBuilder.ConfigureServices(Program.cs)中註冊該服務。

services.AddHostedService<Worker>();

WorkerServices部署到Windows服務

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;


namespace WorkerServiceDemo
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            return Host.CreateDefaultBuilder(args)
               
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                }).UseWindowsService(); ;

        }
    }
}

現在我們可以部署我們的windows服務了。

釋出方式

  • 使用sc.exe工具
  • 直接部署exe檔案

釋出Windows服務

dotnet restore
dotnet publish

sc.exe部署

sc.exe create DemoWorker binpath= publish\xxxx.exe
sc.exe start WorkerServicesName

部署exe檔案

WorkerServicesName.exe install
WorkerServicesName.exe start

使用sc.exe停止和刪除

sc.exe stop WorkerServicesName 
sc.exe delete WorkerServicesName 

非sc.exe停止和刪除

WorkerServicesName stop  
WorkerServicesName uninstall

在Linux設定守護程式

將UseSystemd()新增上。

        public static IHostBuilder CreateHostBuilder(string[] args)
        {

            return Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                }).UseSystemd();

        }

在Linux上設定為守護程式。

Reference

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-3.1&tabs=visual-studio

https://github.com/hueifeng/BlogSample/tree/master/src/WorkerServiceDemo