利用Topshelf把.NET Core Generic Host管理的应用程序部署为Windows服务「建议收藏」

利用Topshelf把.NET Core Generic Host管理的应用程序部署为Windows服务「建议收藏」背景2019第一篇文章。此文源于前公司在迁移项目到.NETCore的过程中,希望使用GenericHost来管理定时任务程序时,没法部署到Windows服务的问题,而且官方也没给出解决方案,只能关注一下官方issue#809等他们方解决了。官方文档只提供了一个《在Windows服务中托管ASP.NETCore》的方案,可以使用Microsoft.AspNetCore.Host…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

背景

2019第一篇文章。

此文源于前公司在迁移项目到.NET Core的过程中,希望使用Generic Host来管理定时任务程序时,没法部署到Windows服务的问题,而且官方也没给出解决方案,只能关注一下官方issue #809 等他们方解决了。

官方文档只提供了一个《在 Windows 服务中托管 ASP.NET Core》的方案,可以使用Microsoft.AspNetCore.Hosting.WindowsServices类库来把Web应用部署为Windows服务。但是ASP.NET Core虽然是控制台程序,但是它本身是使用了含有HTTP管道的Web Host来负责应用程序的生命周期管理,用它来作为定时任务的话,会有很多不必要的工作负载,例如占用端口、增加了很多依赖等等。

官方意识到这个问题之后,在.NET Core 2.1版本新增了Generic Host通用主机,剥离了原来WebHost的Http管道相关的API,源码中可以发现Web Host已经基于Generic Host实现。它才是作为纯粹定时任务程序的最佳拍档。

但是由于Generic Host本身非常简单,用它运行的程序设置在注册为Windows服务启动之后会自动停止。研究很久之后才知道,想在Windows上启动服务,还是不能像Linux上那么简单——

于是尝试结合Topshelf来创建Windows服务,最终成功了。

实现方法

  1. 先实现IHostLifetime接口来接管应用程序的生命周期,其实就是用空的实现来替换掉默认的ConsoleLifetime,这样就可以在之后由Topshelf框架内部去管理生命周期。
    internal class TopshelfLifetime : IHostLifetime
    {
        public TopshelfLifetime(IApplicationLifetime applicationLifetime, IServiceProvider services)
        {
            ApplicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
        }

        private IApplicationLifetime ApplicationLifetime { get; }

        public Task WaitForStartAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
    }
  1. 然后实现IHostedService接口,把后台任务逻辑写到StartAsync方法中,参见官方文档《在 ASP.NET Core 中使用托管服务实现后台任务》,本文示例使用定时写入文本到一个文件来测试定时任务是否成功运行。
    internal class FileWriterService : IHostedService, IDisposable
    {
        private static string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"test.txt");

        private Timer _timer;

        public Task StartAsync(CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested) return Task.FromCanceled(cancellationToken);

            _timer = new Timer(
                (e) => WriteTimeToFile(),
                null,
                TimeSpan.Zero,
                TimeSpan.FromSeconds(10));

            return Task.CompletedTask;
        }

        public void WriteTimeToFile()
        {
            if (!File.Exists(path))
            {
                using (var sw = File.CreateText(path))
                {
                    sw.WriteLine(DateTime.Now);
                }
            }
            else
            {
                using (var sw = File.AppendText(path))
                {
                    sw.WriteLine(DateTime.Now);
                }
            }
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _timer?.Change(Timeout.Infinite, 0);

            return Task.CompletedTask;
        }

        public void Dispose()
        {
            _timer?.Dispose();
        }
    }
  1. 构建Generic Host,在ConfigureServices方法中注册TopshelfLifetime,并且注册一个托管服务FileWriterService,就能完成Generic Host的简单构建,当然完整的项目应该还包含配置、日志等等。最后,使用Topshelf来接管Generic Host,创建Windows服务。
    internal class Program
    {
        private static void Main(string[] args)
        {
            var builder = new HostBuilder()
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddSingleton<IHostLifetime, TopshelfLifetime>();
                    services.AddHostedService<FileWriterService>();
                });

            HostFactory.Run(x =>
            {
                x.SetServiceName("GenericHostWindowsServiceWithTopshelf");
                x.SetDisplayName("Topshelf创建的Generic Host服务");
                x.SetDescription("运行Topshelf创建的Generic Host服务");

                x.Service<IHost>(s =>
                {
                    s.ConstructUsing(() => builder.Build());
                    s.WhenStarted(service =>
                    {
                        service.Start();
                    });
                    s.WhenStopped(service =>
                    {
                        service.StopAsync();
                    });
                });
            });
        }
    }
  1. 最后发布应用程序,并安装到Windows服务。

以管理员权限开启终端,执行命令:

  dotnet publish -c release -r win-x64
  
  cd path-to-project/bin/release/netcoreapp2.1/win-x64/publish

  ./project-name install

  net start GenericHostWindowsServiceWithTopshelf

generic-host-install.png

这样这个Windows服务就启动了!查看输出文件,可以看到定时写入成功,服务也一直没关闭~

generic-host-result.png

示例代码

https://github.com/ElderJames/GenericHostWindowsServiceWithTopshelf

参考链接

官方文档《.NET 通用主机》

官方文档《在 ASP.NET Core 中使用托管服务实现后台任务》

转载于:https://www.cnblogs.com/ElderJames/p/Using-Topshelf-To-Deploy-Net-Core-Generic-Host-App-To-Windows-Services.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/183778.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Grid Search 网格搜索 介绍「建议收藏」

    Grid Search 网格搜索 介绍「建议收藏」什么是GridSearch网格搜索?网格搜素是一种常用的调参手段,是一种穷举方法。给定一系列超参,然后再所有超参组合中穷举遍历,从所有组合中选出最优的一组超参数,其实就是暴力方法在全部解中找最优解。为什么叫网格搜索,因为假设有两个超参,每个超参都有一组候选参数。这两组候选参数可以两两组合,把所有组合列出来就是一个二维的网格(多个超参两两组合可以看作是岗高维空间的网格),遍历网格中的所有节点,选出最优解。所以叫网格搜索。…

    2022年10月21日
    3
  • endnote x9中文版安装教程_vivo怎么强制安装软件

    endnote x9中文版安装教程_vivo怎么强制安装软件一、下载在百度中搜索“Endnotex9”,点第一个链接进入下载页面。软件大小为108MB,下载的是一个压缩包,如下图所示,双击解压之后是右侧的图标,解压到文件夹,双击即可安装。二、安装直接安装即可,可以更换安装路径备注:安装成功后使用汉化版,可以将CHS文件夹里的[EndNote.exe]拷贝到EndNote的安装目录下。使用英文版,可以将ENG文件夹里的[EndNote.exe]拷贝到EndNote的安装目录下。不论用的是英文版还是中文版,替换之后即可使用…

    2022年10月11日
    2
  • 1146 mysql_MySQL–ERROR 1146 (42S02):table doesn’t exist

    1146 mysql_MySQL–ERROR 1146 (42S02):table doesn’t existERROR1146(42S02):Table‘xxx’doesn’texist可能是很多人都遇到的问题,尤其在数据库迁移或备份的时候mysql数据目录结构mysql数据目录下有如下几个重要文件:ibdata1ib_logfile0ib_logfile1数据库xx以及该目录下的一系列.frm文件其中ib_logfile0和ib_logfile1是关于数据库的一些日志文件数据…

    2022年5月2日
    446
  • JAVA大数据后台管理系统

    JAVA大数据后台管理系统一款Java语言基于SpringBoot2.x、Layui、Thymeleaf、MybatisPlus、Shiro、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发、提升开发效率的初衷,自研了一套个性化的组件,实现了可插拔的组件式开发方式:单图上传、多图上传、下拉选择、开关按钮、单选按钮、多选按钮、图片裁剪等

    2022年5月4日
    56
  • 如何查看redis内存使用情况

    如何查看redis内存使用情况

    2021年10月16日
    56
  • 《github一天,一个算术题》:堆算法接口(堆排序、堆插入和堆垛机最大的价值,并删除)

    《github一天,一个算术题》:堆算法接口(堆排序、堆插入和堆垛机最大的价值,并删除)

    2022年1月10日
    45

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号