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.CoreMyCompanyName.AbpZeroTemplate.Core项目

  3. 最终引用如图:

  4. 创建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()); }
    }
    }
  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和插件支持.(注意路径)
      var services = new ServiceCollection();
      IdentityRegistrar.Register(services); services.AddAbp<AbpZeroWinServiceModule>(options =>
      {
      //Configure Log4Net logging
      options.IocManager.IocContainer.AddFacility<LoggingFacility>(
      f => f.UseAbpLog4Net().WithConfig(Path.Combine(currentDirectory, $"log4net.config"))
      ); options.PlugInSources.AddFolder(Path.Combine(currentDirectory, "Plugins"), SearchOption.AllDirectories);
      });

    完整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); services.AddAbp<AbpZeroWinServiceModule>(options =>
    {
    //Configure Log4Net logging
    options.IocManager.IocContainer.AddFacility<LoggingFacility>(
    f => f.UseAbpLog4Net().WithConfig(Path.Combine(currentDirectory, $"log4net.config"))
    ); options.PlugInSources.AddFolder(Path.Combine(currentDirectory, "Plugins"), SearchOption.AllDirectories);
    }); 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");
    });
    }
    }
  6. 启动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;
    }
    }
  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

最新文章

  1. Android性能优化
  2. Linux命令详解nice
  3. 【网络收集】MySql中IS NOT NULL与!=NULL的区别
  4. Android 通过广播启动另一个应用的Activity
  5. java获取计算机硬件参数
  6. logstash match
  7. 关于Java配置文件properties的学习
  8. raise()函数
  9. Spring MVC Json数据传递
  10. window.settimeout用法与window.setInterval用法的区别
  11. Python 项目实践一(外星人入侵)第一篇
  12. Kerberos原理
  13. Django admin组件源码流程
  14. CentOS 7.5 安装 Python3.7
  15. 【转】C++标准转换运算符reinterpret_cast
  16. 转://Linux MultiPath多路径软件实施说明
  17. vue项目打包后一片空白及资源引入的路径报错解决办法
  18. Python 调用 Redis API
  19. MySQL -- 全文检索
  20. 【linux系列】centos安装vsftp

热门文章

  1. 导出Telegram贴纸
  2. Linux cut 命令详解
  3. 更改docker默认存储路径操作(centos6版本)
  4. Java+MySQL企业级实训全套课程
  5. seaborn分类数据可视化:散点图|箱型图|小提琴图|lv图|柱状图|折线图
  6. OnePill本地保存用户的结构
  7. 【Django组件】WebSocket的简单实现
  8. 《谁说菜鸟不会数据分析》高清PDF全彩版|百度网盘免费下载|Python数据分析
  9. Java线程池ThreadPoolExecutor面试总结思维导图速记
  10. Blob分析之bottle.hdev