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

Aspnet Zero中使用Windows service (Topshelf)来承载Quartz.net任务的更多相关文章

  1. Win7中不能调试windows service

    多年前玩过一次windows service,觉得挺简单的. 这次工作要维护产品中的windows service,发现不是那么简单,vs附加调试器的窗体中无法找到windows service进程. ...

  2. WCF Windows Service Using TopShelf and ServiceModelEx z

    http://lourenco.co.za/blog/2013/08/wcf-windows-service-using-topshelf-and-servicemodelex/ There are ...

  3. 创建需要计时器的windows service

    1.在VS中建立windows service后,应该添加一个安装程序. 2.在默认的Service1.cs设计界面右键,添加安装程序,生成ProjectInstaller.包含两个类serviceP ...

  4. C# 通过 Quartz .NET 实现Timer Job并将其注册成为Windows Service

    之前的一篇文章讲述了如何通过 Quartz .NET 实现 Timer Job (http://www.cnblogs.com/mingmingruyuedlut/p/8037263.html) 在此 ...

  5. .NET 6学习笔记(2)——通过Worker Service创建Windows Service

    通过Visual Studio中的Windows Service模板,我么可以创建.NET Framework版本的Windows Service,网络上对此已有详细且丰富的各路教程.但在我们升级到. ...

  6. 如何托管ASP.NET Core应用到Windows Service中

    (此文章同时发表在本人微信公众号"dotNET开发经验谈",欢迎右边二维码来关注.) 题记:正在构思一个中间件的设计,考虑是否既可以使用最新的技术,也可以兼顾传统的部署模式.所以有 ...

  7. .NET开发Windows Service程序 - Topshelf

    在实际项目开发过程中,会经常写一些类似定时检查,应用监控的应用.这类应用在windows平台通常都会写成window service程序. 在百度上搜索一下'c#开发windows service', ...

  8. quartz.net结合Topshelf实现windows service服务托管的作业调度框架

    topshelf可以很简单方便的实现windows service服务,详见我的一篇博客的介绍 http://www.cnblogs.com/xiaopotian/articles/5428361.h ...

  9. ASP.NET Core应用到Windows Service中

    托管到Windows Service中 众所周知,ASP.NET Core采用了和传统ASP.NET不同的托管和HTTP处理方式,即把服务器和托管环境完全解耦. ASP.NET Core内置了两个HT ...

随机推荐

  1. Flarum 的安装与配置

    Flarum 是一款非常棒的开源论坛程序,本鸽子的论坛 就是用 Flarum 搭建的.之前有人问过我 Flarum 如何搭建,所以下面讲一下 Flarum 的搭建过程. 前提 域名需要提前解析. 有一 ...

  2. CppUnit使用和源码解析

    前言 CppUnit是一个开源的单元测试框架,支持Linux和Windows操作系统,在linux上可以直接进行源码编译,得到动态库和静态库,直接链接就可以正常使用,在Windows上可以使用VC直接 ...

  3. ST表解决RMQ问题

    RMQ问题: RMQ(Range Minimum/Maximum Query),区间最值查询.对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间 ...

  4. Problem H: 质心算法

    Description 在很多应用中,需要对某个目标进行定位.比如对于一个未知坐标的点A,假定已知A点与N个点相邻,且已知N个相邻点的坐标,则可取N个点的质心作为A点坐标的一个估计值. 所谓质心,就是 ...

  5. 离线安装 docker

    1.基础环境 操作系统:CentOS 7.8 docker 版本:18.06.1 2.docker 下载 2.1 官方地址 https://download.docker.com/linux/stat ...

  6. Java 线程池记录

    Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程.newFixe ...

  7. isinstance方法判断可迭代和迭代器

    from collections import Iterable print(isinstance([],Iterable)) print(isinstance( {}, Iterable)) pri ...

  8. Python long() 函数

    描述 long() 函数将数字或字符串转换为一个长整型.高佣联盟 www.cgewang.com 语法 long() 函数语法: class long(x, base=10) 参数 x -- 字符串或 ...

  9. PHP connection_status() 函数

    实例 返回连接状态: <?phpswitch (connection_status()){高佣联盟 www.cgewang.comcase CONNECTION_NORMAL:$txt = 'C ...

  10. 5.5 省选模拟赛 B Permutation 构造 贪心

    LINK:Permutation 对于这种构造神题 我自然是要补的.为啥就我没想出来哇. 30分还是很好写的 注意8!实际上很小 不需要爆搜 写bfs记录状态即可.至于判断状态是否出现与否 可以开ma ...