Aspnet Zero中使用Windows service (Topshelf)来承载Quartz.net任务
Aspnet Zero使用Windows service (Topshelf)来承载Quartz.net任务
网上有很多关于如何使用Topshelf创建ABP的Quartz windows服务,但很少(没有)有介绍如何配合Aspnet Zero使用的文章,本文记录集成过程,以供参考。
-
在官方Aspnet Zero模板解决方案中建立Console类型的项目,并安装以下nuget package:
Topshelf
Abp.Quartz
Abp.Castle.Log4Net
-
添加引用
MyCompanyName.AbpZeroTemplate.Core
和MyCompanyName.AbpZeroTemplate.EntityFrameworkCore
项目 -
最终引用如图:
-
创建Module文件,
- 添加相关DependsOn属性;
abpZeroTemplateEntityFrameworkCoreModule.SkipDbSeed = true;
这里我们需要禁用数据库初始化动作,因为所有的初始化动作都在Host端完成;- 设置数据库连接字符串
Configuration.DefaultNameOrConnectionString = _appConfiguration.GetConnectionString( AbpZeroTemplateConsts.ConnectionStringName );
最终文件如下:
namespace MyCompanyName.AbpZeroTemplate.WinService { [DependsOn(typeof(AbpZeroTemplateCoreModule), typeof(AbpZeroTemplateEntityFrameworkCoreModule), typeof(AbpQuartzModule) )] public class AbpZeroWinServiceModule : AbpModule { private readonly IConfigurationRoot _appConfiguration; public AbpZeroWinServiceModule(AbpZeroTemplateEntityFrameworkCoreModule abpZeroTemplateEntityFrameworkCoreModule) { abpZeroTemplateEntityFrameworkCoreModule.SkipDbSeed = true; _appConfiguration = AppConfigurations.Get( typeof(AbpZeroWinServiceModule).GetAssembly().GetDirectoryPathOrNull(), addUserSecrets: true ); } public override void PreInitialize() { //Set default connection string Configuration.DefaultNameOrConnectionString = _appConfiguration.GetConnectionString( AbpZeroTemplateConsts.ConnectionStringName ); } public override void Initialize() { this.IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); } } }
-
修改Program.cs文件
- 设置工作目录
Directory.SetCurrentDirectory(currentDirectory);
, 目的是为了保证工作在windows service时log文件存放目录正确,如果不设置, 工作在windows service时log文件将会存放在system32目录中 - 注册IdentityRegistrar以及添加abp依赖,这一步是必须的,否则会出现依赖错误:
Castle.MicroKernel.Handlers.HandlerException: 'Can't create component 'Portal.Authorization.Users.UserManager' as it has dependencies to be satisfied.
添加abp依赖的同时我们同时添加log4net和插件支持.(注意路径)var services = new ServiceCollection(); IdentityRegistrar.Register(services); var abpBootstrapper = AbpBootstrapper.Create<AbpZeroWinServiceModule>(options => { options.IocManager.IocContainer.AddFacility<LoggingFacility>( f => f.UseAbpLog4Net().WithConfig(Path.Combine(currentDirectory, $"log4net.config")) ); options.PlugInSources.AddFolder(Path.Combine(currentDirectory, "Plugins"), SearchOption.AllDirectories); }); services.AddSingleton(abpBootstrapper); abpBootstrapper.IocManager.IocContainer.AddServices(services);
完整Program.cs代码如下:
class Program { static void Main(string[] args) { var currentDirectory = typeof(Program).GetAssembly().GetDirectoryPathOrNull(); // 设置工作目录. 保证工作在windows service时log文件存放目录正确 // 如果不设置, 工作在windows service时log文件将会存放在system32目录中 Directory.SetCurrentDirectory(currentDirectory); var services = new ServiceCollection(); IdentityRegistrar.Register(services); var abpBootstrapper = AbpBootstrapper.Create<AbpZeroWinServiceModule>(options => { options.IocManager.IocContainer.AddFacility<LoggingFacility>( f => f.UseAbpLog4Net().WithConfig(Path.Combine(currentDirectory, $"log4net.config")) ); options.PlugInSources.AddFolder(Path.Combine(currentDirectory, "Plugins"), SearchOption.AllDirectories); }); services.AddSingleton(abpBootstrapper); abpBootstrapper.IocManager.IocContainer.AddServices(services); HostFactory.Run(x => { x.Service<AbpZeroWinService>(s => { s.ConstructUsing(name => new AbpZeroWinService()); s.WhenStarted((tc, hostControl) => tc.Start(hostControl)); s.WhenStopped((tc, hostControl) => tc.Stop(hostControl)); }); x.RunAsLocalSystem(); x.StartAutomatically(); x.SetDescription("ABP服务测试"); x.SetDisplayName("ABPTestService"); x.SetServiceName("ABPTestService"); }); } }
- 设置工作目录
-
启动ABP. Windows service启动时会调用
s.ConstructUsing(name => new AbpZeroWinService());
, 因此我们在AbpZeroWinService
中启动ABP.- 创建
AbpZeroWinService
类继承自ServiceControl
, 在Start
中初始化AbpBootstrapper
, 同时在停止Stop
中销毁AbpBootstrapper
. 代码如下:
public class AbpZeroWinService : ServiceControl { private AbpBootstrapper _bootstrapper; public bool Start(HostControl hostControl) { _bootstrapper = IocManager.Instance.Resolve<AbpBootstrapper>(); _bootstrapper.Initialize(); return true; } public bool Stop(HostControl hostControl) { _bootstrapper.Dispose(); return true; } }
- 创建
-
quartz.net的配置
quartz.config
中必须使用AdoJobStore
类型,并且使用和Host一样的Quartz数据库连接,这样才能实现在host上添加任务,最终由windows service来执行任务。
(请在HostModule的PreInitialize
方法中禁用Job执行Configuration.BackgroundJobs.IsJobExecutionEnabled = false;
) -
运行前确保Quartz.net数据库已建立,如何建立请参考Quartz.net官方文档
以上如有错误的地方请大家指正! 如果更好的实现方式,也请分享一下。
最后给出WindowService项目的源码,Aspnet Zero的项目自行解决。
source code
posted on 2020-08-12 08:01 Thinking110 阅读(515) 评论(0) 编辑 收藏 举报