1.简单介绍

XAgent为大石头带领下的新生命团队自己开发的一个.Net下的常用的Windows服务管理组件利器,通过在控制台中简单的输入1,2,3,4,5等数字可以实现一步安装、卸载WindowsService以及单步调试和循环调试、服务停止,重启、运行,用起来很方便。看效果(具体使用方法可以去XAgent官网查看):

2.当前使用场景介绍及实现

我的这个项目下面有很多控制台应用程序需要运行,平时部署很麻烦,不方便管理。我的想法是把这些程序以插件的形式放到一个应用程序中运行管理。这里写了一个Ijob接口。看代码:

Ijob相关代码

  1. /// <summary>工作接口</summary>
  2. public interface IJob
  3. {
  4. /// <summary>
  5. /// 工作组件顺序
  6. /// </summary>
  7. int Sort { get; set; }
  8.  
  9. /// <summary>
  10. /// 间隔时间
  11. /// </summary>
  12. int JobInterval { get; set; }
  13.  
  14. /// <summary>启动</summary>
  15. /// <returns></returns>
  16. bool Start();
  17.  
  18. /// <summary>停止</summary>
  19. /// <returns></returns>
  20. bool Stop();
  21.  
  22. /// <summary>工作</summary>
  23. bool Work();
  24.  
  25. //void WriteLog(string format, params object[] args);
  26. }
  27.  
  28. /// <summary>基础工作组件</summary>
  29. public class Job : IJob
  30. {
  31. ///// <summary>
  32. ///// 是否执行
  33. ///// </summary>
  34. //public bool IsExcute { get; set; }
  35.  
  36. public Job()
  37. {
  38. Sort = ;
  39. DisplayName = "基础工作组件";
  40. JobInterval = ; //默认60秒
  41. //IsExcute = true;//默认执行
  42. }
  43.  
  44. /// <summary>工作组件名</summary>
  45. public virtual string DisplayName { get; set; }
  46.  
  47. /// <summary>工作组件顺序</summary>
  48. public virtual int Sort { get; set; }
  49.  
  50. /// <summary>
  51. /// 时间间隔
  52. /// </summary>
  53. public int JobInterval { get; set; }
  54.  
  55. /// <summary>启动</summary>
  56. public virtual bool Start()
  57. {
  58. WriteLog("开始工作");
  59. return false;
  60. }
  61.  
  62. /// <summary>停止</summary>
  63. /// <returns></returns>
  64. public virtual bool Stop()
  65. {
  66. WriteLog("停止工作");
  67. return false;
  68. }
  69.  
  70. /// <summary>工作</summary>
  71. public virtual bool Work()
  72. {
  73. WriteLog("正在运行");
  74. return false;
  75. }
  76.  
  77. public virtual void WriteLog(string format, params object[] args)
  78. {
  79. //XTrace.WriteLine("[" + this.GetType() + "] [" + DisplayName + "] " + format, args);
  80. XTrace.WriteLine("[" + DisplayName + "] " + format, args);
  81. }
  1. public static class JobHelper
  2. {
  3. static readonly List<Type> _hasInited = new List<Type>();
  4.  
  5. private static List<IJob> op_cache = new List<IJob>();
  6.  
  7. /// <summary>所有工作组件</summary>
  8. public static List<IJob> Works
  9. {
  10. get
  11. {
  12. var list = LoadWork();
  13. foreach (var item in list)
  14. {
  15. EnsureInit(item);
  16. }
  17. op_cache = op_cache.OrderBy(j => j.Sort).ToList();
  18. return op_cache;
  19. }
  20. }
  21.  
  22. /// <summary>确保实体类已经执行完静态构造函数,因为那里实在是太容易导致死锁了</summary>
  23. /// <param name="type">类型</param>
  24. internal static void EnsureInit(Type type)
  25. {
  26. if (_hasInited.Contains(type)) return;
  27. // 先实例化,在锁里面添加到列表但不实例化,避免实体类的实例化过程中访问CreateOperate导致死锁产生
  28. var item = type.CreateInstance();
  29. lock (_hasInited)
  30. // 如果这里锁定_hasInited,还是有可能死锁,因为可能实体类A的静态构造函数中可能导致调用另一个实体类的EnsureInit
  31. // 其实我们这里加锁的目的,本来就是为了避免重复添加同一个type而已
  32. //lock ("_hasInited" + type.FullName)
  33. {
  34. if (_hasInited.Contains(type)) return;
  35.  
  36. if (op_cache.Contains(item as IJob)) return;
  37. op_cache.Add(item as IJob);
  38.  
  39. //type.CreateInstance();
  40. _hasInited.Add(type);
  41. }
  42. }
  43.  
  44. /// <summary>列出所有工作接口</summary>
  45. /// <returns></returns>
  46. public static List<Type> LoadWork()
  47. {
  48. return typeof (IJob).GetAllSubclasses(true).ToList();
  49. }
  50. }

确保所有的工作组件继承Job类,重写其中的方法,将一些需要配置的属性做成xml进行管理。废话不说看代码:

这是其中一个工作插件

  1. public HourStatisticsWork()
  2. {
  3.  
  4. DisplayName = "小时统计组件";
  5. Sort = ;
  6.  
  7. if (WorkSetting.Current.HourStatisticsEnable)
  8. {
  9. JobInterval = WorkSetting.Current.HourStatisticsInterval;
  10. }
  11. else
  12. {
  13. JobInterval = -; //禁用此组件
  14. }
  15. }
  16.  
  17. public override bool Work()
  18. {
  19. StartWork();
  20. return base.Work();
  21. }
  22. public override bool Stop()
  23. {
  24. if (_HourTimer != null)
  25. {
  26. _HourTimer.Dispose();
  27. }
  28. return base.Stop();
  29. }
  30. public void StartWork()
  31. {
  32. try
  33. {
  34. // Console.WriteLine("当前时间{0}",DateTime.Now);
  35. //var time = WorkSetting.Current.HourStatisticsInterval;
  36. //// 定时器一分钟后启动
  37. //if (_HourTimer == null)
  38. // _HourTimer = new TimerX(obj =>
  39. // {
  40.  
  41. // StartWork();
  42. // }, null, 3 * 1000, time);
  43. DateTime dt = DateTime.Now.AddHours(-);
  44. cyStatistics(dt);
  45. sccStatistics(dt);
  46. ccStatistics(dt);
  47. jcStatistics(dt);
  48. mfStatistics(dt);
  49. vcStatistics(dt);
  50. vbStatistics(dt);
  51. pulStatistics(dt);
  52. icStatistics(dt);
  53. rhcStatistics(dt);
  54. dtrStatistics(dt);
  55.  
  56. MotorLoadStatistics(dt);
  57. TimeStatistics(dt);
  58. Container.Info("[HourStatisticsWork]Hour Statistics");
  59. }
  60. catch (Exception ex)
  61. {
  62. Container.Error($"[HourStatisticsWork]{ex.Message}");
  63. }
  64.  
  65. }

相关配置项

  1. [DisplayName("运行参数设置")]
  2. [XmlConfigFile(@"Config\WorkSetting.config", )]
  3. public class WorkSetting : XmlConfig<WorkSetting>
  4. {
  5. //private String _LastTool;
  6. ///// <summary>最后一个使用的工具</summary>
  7. //[DisplayName("最后一个使用的工具")]
  8. //public String LastTool { get { return _LastTool; } set { _LastTool = value; } }
  9.  
  10. protected override void OnNew()
  11. {
  12. SystemName = "物联网监控系统";
  13. LastUpdateTime = new DateTime(, , );
  14.  
  15. RabbitMqResolveEnable = true;
  16. RabbitMqResolveInterval = ;//默认1s
  17. HourStatisticsEnable = true;
  18. HourStatisticsInterval = *;//默认30min
  19.  
  20. DayStatisticsEnable = true;
  21. DayStatisticsInterval = * *;//默认12个小时
  22.  
  23. EnableViewServiceLog = false;
  24. }
  25.  
  26. #region 队列解析
  27.  
  28. [Description("启用队列解析")]
  29. public bool RabbitMqResolveEnable { get; set; }
  30. [Description("队列解析间隔时间,单位:秒")]
  31. public int RabbitMqResolveInterval { get; set; }
  32.  
  33. #endregion
  34.  
  35. #region 小时统计
  36.  
  37. [Description("启用小时统计")]
  38. public bool HourStatisticsEnable { get; set; }
  39. [Description("小时统计间隔时间,单位:秒")]
  40. public int HourStatisticsInterval { get; set; }
  41. #endregion
  42.  
  43. #region 自然日统计
  44.  
  45. [Description("启用自然日统计")]
  46. public bool DayStatisticsEnable { get; set; }
  47. [Description("自然日统计间隔时间,单位:秒")]
  48. public int DayStatisticsInterval { get; set; }
  49. #endregion
  50.  
  51. #region 异常通知
  52.  
  53. [Description("启用异常通知")]
  54. public bool ExceptionNotifyEnable { get; set; }
  55.  
  56. [Description("异常通知级别")]
  57. public int ExceptionNotifyLevel { get; set; }
  58.  
  59. #endregion 异常通知
  60.  
  61. #region 系统
  62.  
  63. /// <summary>
  64. /// 系统名称
  65. /// </summary>
  66. [Description("系统名称")]
  67. public String SystemName { get; set; }
  68.  
  69. /// <summary>最后更新时间</summary>
  70. [Description("最后更新时间")]
  71. public DateTime LastUpdateTime { get; set; }
  72.  
  73. #endregion 系统
  74.  
  75. #region Windows Service
  76.  
  77. /// <summary>服务名</summary>
  78. [Description("服务名")]
  79. public String ServiceName { get; set; }
  80.  
  81. /// <summary>显示名</summary>
  82. [Description("显示名")]
  83. public String DisplayName { get; set; }
  84.  
  85. /// <summary>服务描述</summary>
  86. [Description("服务描述")]
  87. public String Description { get; set; }
  88.  
  89. /// <summary>查看服务运行日志</summary>
  90. [Description("查看服务运行日志")]
  91. public bool EnableViewServiceLog { get; set; }
  92.  
  93. #endregion Windows Service
  94. }

一切准备好后,开始生成项目并运行,效果如下:

3.发现问题

看起来一切运行正常,但是等到我讲xml文件中的HourStatisticsEnable设置成false时,发现只有第一个队列解析的服务在运行。第三个自然日统计的服务没有运行。这时我注意到,原来是插件运行的先后顺序影响的,即Sort属性。本质上还是JobInterval控制了改插件是否运行。可能XAgent的源代码有些小问题,我没有继续深入到源代码中去查找解决,而是直接通过xml配置文件的Enable判断该组件是否运行。

代码如下:

  1. public HourStatisticsWork()
  2. {
  3.  
  4. if (WorkSetting.Current.HourStatisticsEnable)
  5. {
  6. DisplayName = "小时统计组件";
  7. Sort = ;
  8. JobInterval = WorkSetting.Current.HourStatisticsInterval;
  9. }
  10. else
  11. {
  12. //JobInterval = -1; //禁用此组件
  13. }
  14. }
  15.  
  16. public override bool Work()
  17. {
  18. if (WorkSetting.Current.HourStatisticsEnable)
  19. {
  20. StartWork();
  21. }
  22. return base.Work();
  23. }
  24. public override bool Stop()
  25. {
  26. if (_HourTimer != null)
  27. {
  28. _HourTimer.Dispose();
  29. }
  30. return base.Stop();
  31. }
  32. public void StartWork()
  33. {//todo}

另外,该IJob接口借鉴了我曾经的领导的想法。

供大家学习,如有不正不妥之处请大家指正。谢谢!

需要源码的或者帮助的联系我QQ:694666781

windows服务插件利器-新生命组件XAgent使用心得的更多相关文章

  1. 新生命组件XAgent使用心得

    1.简单介绍 XAgent为大石头带领下的新生命团队自己开发的一个.Net下的常用的Windows服务管理组件利器,通过在控制台中简单的输入1,2,3,4,5等数字可以实现一步安装.卸载Windows ...

  2. 【总结】探索Newlife组件:服务代理利器XAgent的前世今生

         本博客所有文章分类的总目录:http://www.cnblogs.com/asxinyu/p/4288836.html Newlife XCode组件相关文章目录:http://www.cn ...

  3. 配置jboss为windows服务

    先确保jdk和jboss的环境变量是正常可用的 1.(下载binaries 2.x.x-windows x86)找到service.bat和jbosssvc.exe两个文件 1.1 binaries ...

  4. 制作Windows服务和安装程序(C#版)

    http://blog.sina.com.cn/s/blog_5f4ffa170100vt2b.html 1.创建服务项目: 打开VS 2005 编程环境,在C#中新建Windows服务程序 2.将安 ...

  5. 使用 Topshelf 组件一步一步创建 Windows 服务 (2) 使用Quartz.net 调度

    上一篇说了如何使用 Topshelf 组件快速创建Windows服务,接下来介绍如何使用 Quartz.net 关于Quartz.net的好处,网上搜索都是一大把一大把的,我就不再多介绍. 先介绍需要 ...

  6. 使用Topshelf组件构建简单的Windows服务

    很多时候都在讨论是否需要了解一个组件或者一个语言的底层原理这个问题,其实我个人觉得,对于这个问题,每个人都有自己的看法,个人情况不同,选择的方式也就会不同了.我个人觉得无论学习什么,都应该尝试着去了解 ...

  7. js replace 全局替换 以表单的方式提交参数 判断是否为ie浏览器 将jquery.qqFace.js表情转换成微信的字符码 手机端省市区联动 新字体引用本地运行可以获得,放到服务器上报404 C#提取html中的汉字 MVC几种找不到资源的解决方式 使用Windows服务定时去执行一个方法的三种方式

    js replace 全局替换   js 的replace 默认替换只替换第一个匹配的字符,如果字符串有超过两个以上的对应字符就无法进行替换,这时候就要进行一点操作,进行全部替换. <scrip ...

  8. Windows Service插件服务开源

    WindowsService 插件服务是一个为简化NTService开发和打包程序,提供插件开发的方式进行动态加入或删除业务. 插件式服务程序的由来,在系统维护的过程中,根据企业的要求经常要进行一些周 ...

  9. C# 使用Vici WinService组件来创建Windows服务

    Vici WinService 是 Windows平台下使用C#开发的轻量级用于创建,删除服务的类库,您只需简单的几行代码即可实现多线程异步服务的创建,删除,运行 废话不多说,直接上代码 /***** ...

随机推荐

  1. vue23:vue-loader

    vue-loader: 其他loader -> css-loader.url-loader.html-loader..... 后台: nodeJs(模块化) -> require expo ...

  2. SpringBoot结合MongoDB入门

    MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系 ...

  3. Web API总结

    1.Web API 控制器(Controller) 继承ApiController 2. Api 的 Url Map: api/{controller}/{id} 每个"Action&quo ...

  4. 分享一段官date函数用法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. IPv4私有IP地址有哪些!

    私有IP地址是一段保留的IP地址.只是使用在局域网中,在Internet上是不使用的. 私有IP地址的范围有: 私网地址分有三类, A类中,第一段为10的都为私网地址,B类中,以172.16--172 ...

  6. 【Django】Web框架本质

    目录 根据不同的路径返回不同的内容 普通版 函数版 函数进阶版 返回具体的HTML文件 让网页动态起来 服务器和应用程序 wsgiref 模块 @ * 我们可以这样理解:所有的==Web应用本质上就是 ...

  7. PHP 相关配置

    1. php-fpm的pool 编辑"php-fpm"配置文件"php-fpm.con" vim /usr/local/php/etc/php-fpm.conf ...

  8. 二进制部署mysql5.6

    二进制部署不用编译直接配置环境,初始化就可以使用了下面是官网给的方法: MySQL 二进制安装解决依赖yum install libaio shell> yum search libaio # ...

  9. IOS的四种数据存储方式及优劣

    IOS有四种经常使用数据存储方式: 第一种方法:用NSUserDefaults存储配置信息 NSUserDefaults被设计用来存储设备和应用的配置信息.它通过一个工厂方法返回默认的.也是最经常使用 ...

  10. php数组合并有哪三种方法

    php数组合并有哪三种方法 一.总结 一句话总结:array_merge():array_merge_recursive():‘+'号 $a = array('color'=>'red',5,6 ...