前言
最近公司有个定时发邮件的需求,就是另一个产品会生成很多邮件,但由于这个产品太过老了,而且开发商并不是我方,这些邮件无法发送给相关收邮件的人,于是就想通过.Net Core里的通用主机(官方叫:辅助角色服务应用程序),做成一个Window服务,实现这一功能。
环境
运行环境:.Net 5
开发环境:VS2019 16.8.2
安装
在创建页面找到Worker Service模板
初始化完:
public class Program
{
public static void Main(string[] args)
{
var host=CreateHostBuilder(args).Build();
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
});
}
从代码中发现特别熟悉,跟Asp.Net Core Web几乎一模一样,只不过没有监听http请求,而是通过依赖注入的方式注入了一个继承BackgroundService的类
相当于这里继承BackgroundService就实现了一个能长时间运行的主机服务,那就很简单了,只需要把发送邮件的放在ExecuteAsync,需求是有三个mysql数据库,每隔5分钟去查一次,如果有邮件,则发送给相关方,我这里用的是Dapper+mysql,所以通过依赖注入实现了Dapper的创建。
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly DapperClient _qid1;
private readonly DapperClient _qid2;
private readonly DapperClient _qid3;
public Worker(ILogger<Worker> logger,IDapperFactory dapperFactory)
{
_logger = logger;
this._qid1 = dapperFactory.CreateClient("qid1");
this._qid2 = dapperFactory.CreateClient("qid2");
this._qid3 = dapperFactory.CreateClient("qid3");
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
_logger.LogInformation($"Send Email Service running at: {DateTimeOffset.Now}");
Task t1= SendEmailTask(_qid1, stoppingToken);
Task t2= SendEmailTask(_qid2, stoppingToken);
Task t3 = SendEmailTask(_qid3, stoppingToken);
await Task.WhenAll(t1, t2,t3);
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
protected async Task SendEmailTask(DapperClient dapper,CancellationToken stoppingToken)
{
await Task.Run(async () =>
{
while (!stoppingToken.IsCancellationRequested)
{
EmailHandler handler = new EmailHandler(dapper);
await handler.SearchEmailServer();
await Task.Delay(new TimeSpan(0, 0, 5, 0));
}
},stoppingToken);
}
}
部署
正常情况下,在服务主机上打开.exe文件就能正常运行了,但考虑到别的同事可能会误关程序,于是需要把这个服务注册成一个系统的服务。
需要在CreateHostBuilder中加上 .UseWindowsService()
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
})
.UseWindowsService();
通过windows自带的sc.exe 工具(需要管理员权限),进入cmd命令行,
sc.exe create DemoWorker binpath= publish\xxxx.exe 创建服务
sc.exe start WorkerServicesName 启动服务
sc.exe stop WorkerServicesName 停止服务
sc.exe delete WorkerServicesName 删除服务
另外可以通过管理工具,进入服务,找到服务,设置为自动启动,这样就算服务器关机重启了,也能正常工作。