1. 程式人生 > >Aspnet Zero中使用Windows service (Topshelf)來承載Quartz.net任務

Aspnet Zero中使用Windows service (Topshelf)來承載Quartz.net任務

# Aspnet Zero使用Windows service (Topshelf)來承載Quartz.net任務 網上有很多關於如何使用Topshelf建立ABP的Quartz windows服務,但很少(沒有)有介紹如何配合Aspnet Zero使用的文章,本文記錄整合過程,以供參考。 1. 在官方Aspnet Zero模板解決方案中建立Console型別的專案,並安裝以下buget package: `Topshelf` `Abp.Quartz` `Abp.Castle.Log4Net` `Abp.AspnetCore` (後面有用到) 2. 新增引用`MyCompanyName.AbpZeroTemplate.Core`和`MyCompanyName.AbpZeroTemplate.Core`專案 3. 最終引用如圖: ![](https://img2020.cnblogs.com/blog/28427/202008/28427-20200811115713876-1347830211.png) 4. 建立Module檔案, - 新增相關DependsOn屬性; - `abpZeroTemplateEntityFrameworkCoreModule.SkipDbSeed = true;` 這裡我們需要禁用資料庫初始化動作,因為所有的初始化動作都在Host端完成; - 設定資料庫連線字串`Configuration.DefaultNameOrConnectionString = _appConfiguration.GetConnectionString( AbpZeroTemplateConsts.ConnectionStringName );` 最終檔案如下: ```csharp 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()); } } } ``` 5. 修改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和外掛支援.(注意路徑) ```csharp var services = new ServiceCollection(); IdentityRegistrar.Register(services); services.AddAbp(options => { //Configure Log4Net logging options.IocManager.IocContainer.AddFacility( f => f.UseAbpLog4Net().WithConfig(Path.Combine(currentDirectory, $"log4net.config")) ); options.PlugInSources.AddFolder(Path.Combine(currentDirectory, "Plugins"), SearchOption.AllDirectories); }); ``` 完整Program.cs程式碼如下: ```csharp 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); services.AddAbp(options => { //Configure Log4Net logging options.IocManager.IocContainer.AddFacility( f => f.UseAbpLog4Net().WithConfig(Path.Combine(currentDirectory, $"log4net.config")) ); options.PlugInSources.AddFolder(Path.Combine(currentDirectory, "Plugins"), SearchOption.AllDirectories); }); HostFactory.Run(x => { x.Service(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"); }); } } ``` 6. 啟動ABP. Windows service啟動時會呼叫`s.ConstructUsing(name => new AbpZeroWinService());`, 因此我們在`AbpZeroWinService`中啟動ABP. - 建立`AbpZeroWinService`類繼承自`ServiceControl`, 在`Start`中初始化`AbpBootstrapper`, 同時在停止`Stop`中銷燬`AbpBootstrapper`. 程式碼如下: ```c# public class AbpZeroWinService : ServiceControl { private AbpBootstrapper _bootstrapper; public bool Start(HostControl hostControl) { _bootstrapper = IocManager.Instance.Resolve(); _bootstrapper.Initialize(); return true; } public bool Stop(HostControl hostControl) { _bootstrapper.Dispose(); return true; } } ``` 7. quartz.net的配置`quartz.config`中必須使用`AdoJobStore`型別,並且使用和Host一樣的Quartz資料庫連線,這樣才能實現在host上新增任務,最終由windows service來執行任務。 (**請在HostModule的`PreInitialize`方法中禁用Job執行`Configuration.BackgroundJobs.IsJobExecutionEnabled = false;`**) 8. 執行前確保Quartz.net資料庫已建立,如何建立請參考Quartz.net官方文件 以上如有錯誤的地方請大家指正! 如果更好的實現方式,也請分享一下。 最後給出WindowService專案的原始碼,Aspnet Zero的專案自行解決。 [source code](https://files.cnblogs.com/files/FocusNet/MyCompanyName.AbpZeroTemplate.WinServi