You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

409 lines
16 KiB

2 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Reflection;
  9. using System.ServiceProcess;
  10. using System.Text;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. using System.Transactions;
  14. using System.Xml;
  15. /*==================================================
  16. * Name:
  17. * Author:John.yuan
  18. * Time:2015-01-08
  19. * Modify:
  20. ====================================================*/
  21. namespace TimingTask
  22. {
  23. public partial class TimingTaskService : ServiceBase
  24. {
  25. private string taskConnectionString;
  26. private string logPath;
  27. private long periodSecond;
  28. private List<TimingTaskInfo> taskList;
  29. /// <summary>
  30. /// 構造函數
  31. /// </summary>
  32. public TimingTaskService()
  33. {
  34. InitializeComponent();
  35. XmlDocument docConfig = new XmlDocument();
  36. try
  37. {
  38. docConfig.Load(System.Environment.CurrentDirectory + "/TimingTaskConfig.xml");
  39. XmlNodeList xnl = docConfig.SelectNodes(@"//Tasks");
  40. foreach (XmlNode xn in xnl)
  41. {
  42. taskConnectionString = xn.Attributes["ConnectionString"].Value;
  43. periodSecond = long.Parse(xn.Attributes["Period"].Value);
  44. logPath = xn.Attributes["LogPath"].Value;
  45. }
  46. }
  47. catch (Exception e)
  48. {
  49. WriteLog("TimingTaskService:" + e.Message);
  50. }
  51. }
  52. /// <summary>
  53. /// 初始化定時任務
  54. /// </summary>
  55. private void InitializeTimingTask()
  56. {
  57. XmlDocument docConfig = new XmlDocument();
  58. docConfig.Load(System.Environment.CurrentDirectory + "/TimingTaskConfig.xml");
  59. XmlNodeList xnl = docConfig.SelectNodes(@"//Task[@IsEnabled='Y']");
  60. taskList = new List<TimingTaskInfo>();
  61. foreach (XmlNode xn in xnl)
  62. {
  63. string taskID = xn.Attributes["ID"].Value;
  64. string taskName = xn.Attributes["Name"].Value;
  65. TaskType timingTaskType;
  66. switch (xn.Attributes["TaskType"].Value)
  67. {
  68. case "M":
  69. timingTaskType = TaskType.Month;
  70. break;
  71. case "D":
  72. timingTaskType = TaskType.Day;
  73. break;
  74. case "W":
  75. timingTaskType = TaskType.Week;
  76. break;
  77. case "P":
  78. timingTaskType = TaskType.Period;
  79. break;
  80. default:
  81. WriteLog("InitializeTimingTask:任務類型配置異常。");
  82. continue;
  83. }
  84. DateTime beginTime;
  85. DateTime endTime;
  86. try
  87. {
  88. beginTime = AnalyzeTime(timingTaskType, xn.Attributes["BeginTime"].Value);
  89. endTime = AnalyzeTime(timingTaskType, xn.Attributes["EndTime"].Value);
  90. if (beginTime.Ticks >= endTime.Ticks)
  91. {
  92. WriteLog("InitializeTimingTask:開始時間或結束時間配置異常。");
  93. continue;
  94. }
  95. }
  96. catch (Exception e)
  97. {
  98. WriteLog("InitializeTimingTask:" + e.Message);
  99. continue;
  100. }
  101. long period = long.Parse(xn.Attributes["Period"].Value);
  102. if (beginTime.Ticks > DateTime.Now.Ticks || endTime.Ticks <= DateTime.Now.Ticks)
  103. {
  104. switch (timingTaskType)
  105. {
  106. case TaskType.Day:
  107. beginTime = beginTime.AddDays(1);
  108. endTime = endTime.AddDays(1);
  109. break;
  110. case TaskType.Month:
  111. beginTime = beginTime.AddMonths(1);
  112. endTime = endTime.AddMonths(1);
  113. break;
  114. case TaskType.Week:
  115. beginTime = beginTime.AddDays(7);
  116. endTime = endTime.AddDays(7);
  117. break;
  118. case TaskType.Period:
  119. continue;
  120. default:
  121. WriteLog("InitializeTimingTask:任務類型配置異常。");
  122. continue;
  123. }
  124. }
  125. string className = xn.Attributes["ClassName"].Value;
  126. string assemblyName = xn.Attributes["AssemblyName"].Value;
  127. try
  128. {
  129. Assembly taskAssembly = Assembly.LoadFrom(System.Environment.CurrentDirectory + @"/LIB/" + assemblyName);
  130. Type taskAssType = taskAssembly.GetType(className);
  131. TimingTaskBase.TimingTaskBase timingObj = (TimingTaskBase.TimingTaskBase)Activator.CreateInstance(taskAssType);
  132. TimingTaskInfo taskInfo = new TimingTaskInfo()
  133. {
  134. TaskID = taskID,
  135. TaskName = taskName,
  136. BeginTime = beginTime,
  137. EndTime = endTime,
  138. TaskType = timingTaskType,
  139. TaskObject = timingObj,
  140. Period = period,
  141. LastCompleteTime = null
  142. };
  143. taskList.Add(taskInfo);
  144. }
  145. catch (Exception e)
  146. {
  147. WriteLog("InitializeTimingTask:" + e.Message);
  148. }
  149. }
  150. }
  151. protected override void OnStart(string[] args)
  152. {
  153. try
  154. {
  155. //初始化任務信息
  156. InitializeTimingTask();
  157. InitializeEachTaskTimer();
  158. }
  159. catch (Exception e)
  160. {
  161. WriteLog("OnStart:" + e.Message);
  162. }
  163. }
  164. protected override void OnStop()
  165. {
  166. try
  167. {
  168. using (TransactionScope trans = new TransactionScope())
  169. {
  170. XmlDocument docConfig = new XmlDocument();
  171. docConfig.Load(System.Environment.CurrentDirectory + "/TimingTaskConfig.xml");
  172. foreach (TimingTaskInfo timingInfo in this.taskList)
  173. {
  174. timingInfo.TaskTimer.Change(-1, -1);
  175. XmlNodeList xnl = docConfig.SelectNodes(@"//Tasks[@ID='" + timingInfo.TaskID + "']");
  176. foreach (XmlNode xn in xnl)
  177. {
  178. XmlElement xmlEmt = (XmlElement)xn;
  179. xmlEmt.SetAttribute("LastCompleteTime", timingInfo.LastCompleteTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
  180. }
  181. }
  182. docConfig.Save(System.Environment.CurrentDirectory + "/TimingTaskConfig.xml");
  183. trans.Complete();
  184. }
  185. }
  186. catch (Exception e)
  187. {
  188. WriteLog("OnStop:" + e.Message);
  189. }
  190. }
  191. /// <summary>
  192. /// 計時器回呼函數
  193. /// </summary>
  194. /// <param name="state"></param>
  195. protected void InitializeEachTaskTimer()
  196. {
  197. foreach (TimingTaskInfo timingInfo in this.taskList)
  198. {
  199. if (timingInfo.BeginTime.Ticks <= DateTime.Now.Ticks && DateTime.Now.Ticks < timingInfo.EndTime.Ticks)
  200. {
  201. try
  202. {
  203. if (timingInfo.LastCompleteTime == null || !timingInfo.LastCompleteTime.HasValue)
  204. {
  205. timingInfo.TaskTimer = new Timer(new TimerCallback(TaskExecute), timingInfo, 0, timingInfo.Period);
  206. }
  207. else
  208. {
  209. switch (timingInfo.TaskType)
  210. {
  211. case TaskType.Day:
  212. if (timingInfo.LastCompleteTime.Value.Ticks < timingInfo.BeginTime.Ticks)
  213. {
  214. timingInfo.TaskTimer = new Timer(new TimerCallback(TaskExecute), timingInfo, 0, timingInfo.Period);
  215. }
  216. break;
  217. case TaskType.Week:
  218. if (timingInfo.LastCompleteTime.Value.Ticks < timingInfo.BeginTime.Ticks)
  219. {
  220. timingInfo.TaskTimer = new Timer(new TimerCallback(TaskExecute), timingInfo, 0, timingInfo.Period);
  221. }
  222. break;
  223. case TaskType.Month:
  224. if (timingInfo.LastCompleteTime.Value.Ticks < timingInfo.BeginTime.Ticks)
  225. {
  226. timingInfo.TaskTimer = new Timer(new TimerCallback(TaskExecute), timingInfo, 0, timingInfo.Period);
  227. }
  228. break;
  229. case TaskType.Period:
  230. timingInfo.TaskTimer = new Timer(new TimerCallback(TaskExecute), timingInfo, 0, timingInfo.Period);
  231. break;
  232. default:
  233. WriteLog("任務配置資訊錯誤。");
  234. break;
  235. }
  236. }
  237. }
  238. catch (Exception e)
  239. {
  240. WriteLog("CallEachTask:" + e.Message);
  241. }
  242. }
  243. }
  244. }
  245. /// <summary>
  246. /// 任務執行介面
  247. /// </summary>
  248. /// <param name="state"></param>
  249. private void TaskExecute(object state)
  250. {
  251. using (TransactionScope trans = new TransactionScope())
  252. {
  253. try
  254. {
  255. TimingTaskInfo timingInfo = (TimingTaskInfo)state;
  256. TimingTaskBase.TimingTaskBase timingBase = timingInfo.TaskObject;
  257. timingBase.Run();
  258. timingInfo.LastCompleteTime = DateTime.Now;
  259. trans.Complete();
  260. WriteLog(timingInfo.TaskName + ",執行成功。");
  261. }
  262. catch (Exception e)
  263. {
  264. WriteLog("TaskExecute:" + e.Message);
  265. }
  266. }
  267. }
  268. /// <summary>
  269. /// 分析時間字串
  270. /// </summary>
  271. /// <param name="tkType"></param>
  272. /// <param name="timeString"></param>
  273. /// <returns></returns>
  274. private DateTime AnalyzeTime(TaskType tkType, string timeString)
  275. {
  276. DateTime resultTime;
  277. string[] timeArray = timeString.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  278. if (timeArray.Length < 3 || timeArray.Length > 3)
  279. {
  280. throw new Exception("開始時間或結束時間參數設置錯誤。");
  281. }
  282. switch (tkType)
  283. {
  284. case TaskType.Day:
  285. if ("*" == timeArray[1] || "*" == timeArray[2])
  286. {
  287. throw new Exception("開始時間或結束時間參數設置錯誤。");
  288. }
  289. else
  290. {
  291. resultTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, int.Parse(timeArray[1]), int.Parse(timeArray[2]), 0);
  292. }
  293. break;
  294. case TaskType.Week:
  295. if ("*" == timeArray[0] || "*" == timeArray[1] || "*" == timeArray[2])
  296. {
  297. throw new Exception("開始時間或結束時間參數設置錯誤。");
  298. }
  299. else
  300. {
  301. if ((int)DateTime.Now.DayOfWeek > int.Parse(timeArray[0]))
  302. {
  303. resultTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.AddDays(7 + int.Parse(timeArray[0]) - (int)DateTime.Now.DayOfWeek).Day, int.Parse(timeArray[1]), int.Parse(timeArray[2]), 0);
  304. }
  305. else if ((int)DateTime.Now.DayOfWeek < int.Parse(timeArray[0]))
  306. {
  307. resultTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.AddDays(int.Parse(timeArray[0]) - (int)DateTime.Now.DayOfWeek).Day, int.Parse(timeArray[1]), int.Parse(timeArray[2]), 0);
  308. }
  309. else
  310. {
  311. resultTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, int.Parse(timeArray[1]), int.Parse(timeArray[2]), 0);
  312. }
  313. }
  314. break;
  315. case TaskType.Month:
  316. if ("*" == timeArray[0] || "*" == timeArray[1] || "*" == timeArray[2])
  317. {
  318. throw new Exception("開始時間或結束時間參數設置錯誤。");
  319. }
  320. else
  321. {
  322. if (DateTime.Now.Day > int.Parse(timeArray[0]))
  323. {
  324. resultTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.AddDays(-DateTime.Now.Day).AddMonths(1).AddDays(int.Parse(timeArray[0])).Day, int.Parse(timeArray[1]), int.Parse(timeArray[2]), 0);
  325. }
  326. else
  327. {
  328. resultTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, int.Parse(timeArray[0]), int.Parse(timeArray[1]), int.Parse(timeArray[2]), 0);
  329. }
  330. }
  331. break;
  332. case TaskType.Period:
  333. if ("*" != timeArray[0] && "*" != timeArray[1] && "*" != timeArray[2])
  334. {
  335. resultTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, int.Parse(timeArray[0]), int.Parse(timeArray[1]), int.Parse(timeArray[2]), 0);
  336. }
  337. else if ("*" != timeArray[1] && "*" != timeArray[2])
  338. {
  339. resultTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, int.Parse(timeArray[1]), int.Parse(timeArray[2]), 0);
  340. }
  341. else if ("*" != timeArray[2])
  342. {
  343. resultTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, int.Parse(timeArray[2]), 0);
  344. }
  345. else
  346. {
  347. resultTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, 0);
  348. }
  349. break;
  350. default:
  351. resultTime = DateTime.Now;
  352. break;
  353. }
  354. if (resultTime.Ticks > DateTime.Now.Ticks)
  355. {
  356. return resultTime;
  357. }
  358. else
  359. {
  360. return DateTime.Now;
  361. }
  362. }
  363. /// <summary>
  364. /// 寫定時任務日誌
  365. /// </summary>
  366. /// <param name="strMsg"></param>
  367. private void WriteLog(string strMsg)
  368. {
  369. string strFile = logPath + @"/TimingTaskLog.log";
  370. object objLock = new object();
  371. if (!File.Exists(strFile))
  372. {
  373. File.Create(strFile);
  374. }
  375. lock (objLock)
  376. {
  377. StreamWriter sw = new StreamWriter(strFile, true);
  378. sw.WriteLine(DateTime.Now.ToString());
  379. sw.WriteLine("message text:" + strMsg);
  380. sw.Close();
  381. }
  382. }
  383. }
  384. }