.NET Core Generic Host Windows服务部署使用Topshelf
此文源于前公司在迁移项目到.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|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;
}
}
- 然后实现
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();
}
}
- 构建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();
});
});
});
}
}
- 最后发布应用程序,并安装到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

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

1|2示例代码
https://github.com/ElderJames/GenericHostWindowsServiceWithTopshelf
1|3参考链接
官方文档《.NET 通用主机》
官方文档《在 ASP.NET Core 中使用托管服务实现后台任务》
__EOF__
作 者:ElderJames
.NET Core Generic Host Windows服务部署使用Topshelf的更多相关文章
- .NET Core Generic Host项目使用Topshelf部署为Windows服务
1..NET Core Generic Host是什么? 在.NET Core 2.1版本加入了一种新的Host,即Generic Host(通用主机). 现在在2.1版本的Asp.Net Core中 ...
- .NET CORE QuartzJob定时任务+Windows/Linux部署
前言 以前总结过一篇基于Quartz+Topshelf+.netcore实现定时任务Windows服务 https://www.cnblogs.com/gt1987/p/11806053.html.回 ...
- 使用.NET Core中创建Windows服务(一) - 使用官方推荐方式
原文:Creating Windows Services In .NET Core – Part 1 – The "Microsoft" Way 作者:Dotnet Core Tu ...
- 利用Topshelf把.NET Core Generic Host管理的应用程序部署为Windows服务
背景 2019第一篇文章. 此文源于前公司在迁移项目到.NET Core的过程中,希望使用Generic Host来管理定时任务程序时,没法部署到Windows服务的问题,而且官方也没给出解决方案,只 ...
- dotnet-warp && NSSM 部署 .net core 项目到 windows 服务
如果你想将 .net core 项目以服务的形式部署到 windows 系统,希望本篇文章能够让你少走弯路 dotnet-warp 安装使用 dotnet-warp 是一个全局的.NET Core 工 ...
- .Net Core快速创建Windows服务
1.新建.Net Core控制台程序,添加新建项Windows服务: NuGet引用 System.ServiceProcess.ServiceController,然后修改Progran.cs: c ...
- asp.net core 托管到windows服务,并用iis做反向代理
使用NSSM把.Net Core部署至 Windows 服务 为什么部署至Windows Services 在很多情况下,很少会把.Net Core项目部署至Windows服务中,特别是Asp.n ...
- windows服务部署与卸载
同事问到windows service的东东,现在整理一下,用c#如何创建一个windows service,以及如何调试.部署.卸载. 一.创建windows service 1. 打开VS2008 ...
- windows服务部署
1.新建windows服务项目 2.编辑业务代码 我这里只写2句记录文本的测试代码 using System; using System.IO; using System.ServiceProcess ...
随机推荐
- 【Docker】性能测试监控平台搭建:InfluxDB+Grafana+Jmeter+cAdvisor
前言 在做性能测试时,如果有一个性能测试结果实时展示的页面,可以极大的提高我们对系统性能表现的掌握程度,进而提高我们的测试效率.但是我们每次打开Jmeter都会有几个硕大的字提示别用GUI模式进行负载 ...
- [Java学习] Java方法重载
在Java中,同一个类中的多个方法可以有相同的名字,只要它们的参数列表不同就可以,这被称为方法重载(method overloading). 参数列表又叫参数签名,包括参数的类型.参数的个数和参数的顺 ...
- Android动画(Animations)
动画类型Android的animation由四种类型组成 XML中 alpha : 渐变透明度动画效果 scale :渐变尺寸伸缩动画效果 translate : 画面转换位置移动动画效果 ro ...
- Confluence 6 嵌套用户组的示例
示例 1 : 用是一个子用户组成员 想象在你的目录服务器中,存在下面 2 个用户组: staff marketing 成员: marketing 用户组是 staff 的成员. 用户 jsmith ...
- Confluence 6 使用 LDAP 授权连接一个内部目录 - 用户 Schema 设置
请注意:这部分仅在拷贝用户登录(Copy User on Login)功能被启用后可见. 其他用户 DN(Additional User DN) 这个值被用在进行用户查找和载入的时候来针对 base ...
- vij 1097 贪心
合并果子 描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之 ...
- 对象不能从 DBNull 转换为其他类型
SQL语句:select sum (datediff(second,Begin_Time,End_Time)) as 总时长 from 数据表这是我开始的程序:int 总时长=0;总时长 =Conve ...
- httpclient 连接参数
http.socket.timeout(读取超时) 套接字毫秒级超时时间(SO_TIMEOUT),这就是等待数据,换句话说,在两个连续的数据包之间最大的闲置时间. 如果超时是0表示无限大的超时时间,即 ...
- sgu114. Telecasting station 难度:1
114. Telecasting station time limit per test: 0.25 sec. memory limit per test: 4096 KB Every city in ...
- zoj3732&& hdu4797 Graph Reconstruction
Graph Reconstruction Time Limit: 2 Seconds Memory Limit: 65536 KB Special Judge Let there ...