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. OSCP Learning Notes - Post Exploitation(1)

    Linux Post Exploitation Target Sever: Kioptrix Level 1 1. Search the payloads types. msfvenom -l pay ...

  2. Mysql报Too many connections,不要乱用ulimit了,看看如何正确修改进程的最大文件数

    背景 今天在学习mysql时,看到一个案例,大体来说,就是客户端报Too many connections.但是,客户端的连接池,限制为了200,两个客户端java进程,那也才400,然后mysql配 ...

  3. 【Floyd算法+贪心】 travel 计蒜客 - 45275

    题目: 有 n 个景点,从一个景点 i 旅行到另一个景点 j 要花费 Ai,j=Aj,i(n≤100),现在给出由 m(≤1e5) 个景点的组成序列 A,求:在所有 "有子序列 A 的序列中 ...

  4. xilinx fpga 生成3*3窗口

    在写滤波程序的时候在网上看了好几篇大佬的笔记,都有提到使用3*3窗口,由于小白一个,看到复杂的理论就惧怕的不行.但是现在不得不上,自己调用移位寄存器ip核然后做了个3*3窗口出来,自己动手作出来忽然感 ...

  5. 剑指offo记录

    一.二维数组中的查找 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是 ...

  6. Go语言基础语法总结

    1. 认识HelloWorld 在前面的<Go的安装和使用>这篇文章中已经写过HelloWorld.go了,现在就来逐行认识一下它. package main import "f ...

  7. [转]十分钟带你理解Kubernetes核心概念

    本文将会简单介绍 Kubernetes的核心概念.因为这些定义可以在Kubernetes的文档中找到,所以文章也会避免用大段的枯燥的文字介绍.相反,我们会使用一些图表(其中一些是动画)和示例来解释这些 ...

  8. Redis持久化功能

    Redis为了内部数据的安全考虑,会把本身的数据以文件的形式保存在硬盘中一份,在重启之后会自动把硬盘的数据恢复到内存(redis)里面. 一.snap shotting 快照持久化 该持久化默认开启, ...

  9. Javascript 组成:ECMAscript、Dom、Bom

    一.核心(ECMAScript) ECMAScript 定义的只是这门语言的基础,而在此基础之上可以构建更完善的脚本语言. 二.浏览器对象模型(BOM)——对应window对象 window:窗口 w ...

  10. ubuntu18.04安装opencv+CUDA10.2+cuDNN+YOLOv3

    安装顺序: Opencv 显卡驱动 CUDA10.2 cuDnn YOLOv3 1.Opencv3.2.0安装 搭建依赖环境 sudo apt-get install build-essential ...