.net framework 4.8 开发windows系统服务

2024-08-29 08:12

本文主要是介绍.net framework 4.8 开发windows系统服务,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ps:旧技术了,有一点局限性,但好像网上记录并不多,或是很零散,比较坑人。故自己记录一下。

项目环境:

win 10、.Net framework 4.8,Visual Studio 2019,oracle 12G,ORM是SqlSugar5.1.4.96

一、建项目

1、建项目

新增解决方案文件夹,添加,新建项目,选择windows服务(.net framework),以我个人项目为例,名称为WinService.ReadLog,如下图

2、加入引用

2.1 把实体类库和业务层类库加入。如图

2.2 加入引用Oracle.ManagedDataAccess版本4.122.1.0,加入引用System.Transactions版本4.0.0.0,NuGet管理SqlSugar版本5.1.4.96

二、编码

1、App.config

填上必要参数,包括自定义参数,oracle连接,oracle配置等。

<?xml version="1.0" encoding="utf-8"?>
<configuration><connectionStrings><add name="OracleConn" connectionString="User Id=sajet;Password=tech;Data Source=10.0.1.152/MNCMES;" providerName="Oracle.ManagedDataAccess.Client" /></connectionStrings><appSettings><add key="PLINE" value="A" /><!--测试机--><add key="MACHING_CODE" value="8C1759DD11DE" /><!--同步日志地址--><add key="SYNC_LOGPATH" value="D:\电源自动测试系统\数据库" /></appSettings><startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" /></startup><runtime><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" /></dependentAssembly><dependentAssembly><assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /></dependentAssembly><dependentAssembly><assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" /></dependentAssembly><dependentAssembly><assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" /></dependentAssembly><dependentAssembly><assemblyIdentity name="Oracle.ManagedDataAccess" publicKeyToken="89b483f429c47342" culture="neutral" /><bindingRedirect oldVersion="0.0.0.0-4.122.1.0" newVersion="4.122.1.0" /></dependentAssembly></assemblyBinding></runtime><system.data><DbProviderFactories><remove invariant="Oracle.ManagedDataAccess.Client" /><add name="ODP.NET, Managed Driver" invariant="Oracle.ManagedDataAccess.Client" description="Oracle Data Provider for .NET, Managed Driver" type="Oracle.ManagedDataAccess.Client.OracleClientFactory, Oracle.ManagedDataAccess, Version=4.122.21.1, Culture=neutral, PublicKeyToken=89b483f429c47342" /></DbProviderFactories></system.data>
</configuration>

2、Service1

选中Service1,按F7,进入。参考代码如下,包括计时器的使用,简单的日志记录,服务开启和关闭的正常代码等。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Configuration;
using DAL;
using Model;
using System.Transactions;namespace WinService.ReadLog
{public partial class Service1 : ServiceBase{private Timer timer;string serviceName = "测试机日志读取";public Service1(){InitializeComponent();timer = new Timer(5000); // 设置定时器间隔为60秒  timer.Elapsed += Timer_Elapsed;timer.AutoReset = true;}#region 服务开启protected override void OnStart(string[] args){WriteInfo($"[{serviceName}]服务开启");timer.Start();base.OnStart(args);}#endregion#region 服务关闭protected override void OnStop(){WriteInfo($"[{serviceName}]服务关闭");timer.Stop();base.OnStop();}#endregion#region 轮询事件private void Timer_Elapsed(object sender, ElapsedEventArgs e){try{在这里编写你的轮询逻辑  //string logMessage = $"轮询任务执行于 {DateTime.Now.ToString()}";//WriteLog(logMessage);#region 1.检查配置参数//1.检查配置参数(良品率阈值、产线、测试机、同步日志地址)WriteInfo($"程序启动,检查参数...");string Pline = UnitHelper.GetPline();//产线if (string.IsNullOrEmpty(Pline)){throw new Exception("错误!!缺少参数,“产线”");}string TestMachingCode = UnitHelper.GetTestMachingCode();//测试机string mac = UnitHelper.GetMac();if (string.IsNullOrEmpty(TestMachingCode)){throw new Exception($"错误!!缺少参数,“测试机”。系统检测,物理地址为{mac}");}if (TestMachingCode != mac){throw new Exception("错误!!物理地址不匹配!");}string LogPath = UnitHelper.GetLogPath();//同步日志地址if (string.IsNullOrEmpty(LogPath)){throw new Exception("错误!!缺少参数,“同步日志地址”");}if (!Directory.Exists(LogPath)){throw new Exception("错误!!不存在的路径,“同步日志地址”");}var allLineList = DbHelper.Db.Queryable<SYNC_LINE>().ToList();if (allLineList.Count < 10){throw new Exception("错误!!缺失系统数据(良品率阈值)");}#endregion//2、查看当天日志,读取待更新的数据WriteInfo("开始同步......请勿中途关闭程序!");//查看当天数据是否存在DateTime today = DateTime.Today;string todaFolder = LogPath + "\\" + UnitHelper.DateToString(today);if (!Directory.Exists(todaFolder)){throw new Exception("今日数据未更新!");}//获取当前目录的所有excel文件string[] excelFiles = Directory.GetFiles(todaFolder, "*.xls*", SearchOption.AllDirectories);int succ = 0;//成功数//循环excelfor (int z = 0; z < excelFiles.Count(); z++){//文件完整路径string fullName = excelFiles[z];using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { Timeout = TimeSpan.FromMinutes(10) })){//起始行var fileModel = DbHelper.Db.Queryable<SYNC_READDATA>().Where(a => a.PLINE == Pline &&a.MACHING_CODE == TestMachingCode &&a.FULL_NAME == fullName).First();int startNum = 0;if (fileModel != null){startNum = fileModel.ROW_NO;}//最终行int lastNum = UnitHelper.sheetRowNum(fullName);if (startNum >= lastNum){ts.Complete();//提交throw new Exception("没有更新数据!");}SYNC_READDATA main = new SYNC_READDATA();if (fileModel == null){main.PLINE = Pline;main.MACHING_CODE = TestMachingCode;main.SYNC_LOGPATH = LogPath;main.SYNC_LOGDATE = today;main.FULL_NAME = fullName;main.ROW_NO = lastNum;main.UPDATE_DATE = DateTime.Now;//4.1同步表SYNC_READDATADbHelper.Db.Insertable(main).ExecuteCommand();}else{main = fileModel;main.ROW_NO = lastNum;main.UPDATE_DATE = DateTime.Now;//4.1同步表SYNC_READDATADbHelper.Db.Updateable(main).ExecuteCommand();}main.ID = DbHelper.Db.Ado.GetInt($"select ID from SYNC_READDATA where PLINE='{Pline}' and MACHING_CODE='{TestMachingCode}' and FULL_NAME='{fullName}'");WriteInfo($"读取文件:\r\n {fullName}");List<SYNC_READDATA_REC> recList = new List<SYNC_READDATA_REC>();//读取待更新的数据UnitHelper.GetRecList(main.ID, fullName, TestMachingCode, recList, startNum, lastNum);//4.2同步记录表SYNC_READDATA_RECDbHelper.Db.Insertable(recList).ExecuteCommandAsync();SYNC_RES res = new SYNC_RES();res.MID = main.ID;res.PLINE = Pline;res.CREATEDATE = DateTime.Now;res.ADDNUM = recList.Count;res.BADNUM = recList.Where(a => a.TEST_RES == "FALL").Count();//4.3同步结果表SYNC_RESDbHelper.Db.Insertable(res).ExecuteCommand();var first4 = DbHelper.Db.Queryable<SYNC_CUR_STATISTICS>().Where(a => a.TODAY == today && a.PLINE == Pline).First();if (first4 == null){SYNC_CUR_STATISTICS curStatistics = new SYNC_CUR_STATISTICS();curStatistics.TODAY = today;curStatistics.PLINE = Pline;curStatistics.TOTAL = res.ADDNUM;curStatistics.BADNUM = res.BADNUM;curStatistics.GP = Convert.ToDecimal((curStatistics.TOTAL - curStatistics.BADNUM)) / curStatistics.TOTAL;curStatistics.GOAL = allLineList.Where(a => a.PLINE == Pline).First().GOAL;curStatistics.ALERT = curStatistics.GP < curStatistics.GOAL ? 1 : 0;//是否报警curStatistics.LIFT = 0;curStatistics.ALERT_FLAG = curStatistics.ALERT;//报警状态//4.4同步结果表SYNC_CUR_STATISTICSDbHelper.Db.Insertable(curStatistics).ExecuteCommand();}else{first4.TOTAL = first4.TOTAL + res.ADDNUM;first4.BADNUM = first4.BADNUM + res.BADNUM;first4.GP = Convert.ToDecimal((first4.TOTAL - first4.BADNUM)) / first4.TOTAL;first4.ALERT = first4.GP < first4.GOAL ? 1 : 0;if (first4.LIFT == 0 && first4.ALERT == 1){first4.ALERT_FLAG = 1;//报警状态}//4.4同步结果表SYNC_CUR_STATISTICSDbHelper.Db.Updateable(first4).WhereColumns(it => new { it.TODAY, it.PLINE }).ExecuteCommand();}ts.Complete();//提交}succ++;WriteInfo("成功导入:\r\n " + fullName);}if (succ == excelFiles.Count()){WriteInfo("全部同步完成");WriteInfo("--------------------------------------------------------");}}catch (Exception ex){WriteInfo(ex.Message);}finally{WriteInfo("程序结束");}}#endregion#region 日志//string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MyPollingService.log");private void WriteInfo(string message){string catalog = @"d:/WinServiceLog/mpreadlog/";//判断有无目录,没有自动创建if (!Directory.Exists(catalog)){Directory.CreateDirectory(catalog);}string logPath = catalog + DateTime.Now.ToString("yyyy-MM-dd")+".log";File.AppendAllText(logPath, $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} - {message}{Environment.NewLine}");}#endregion}
}

3、添加安装程序

双击Service1.cs,添加安装程序,得到ProjectInstaller.cs

3.1 选择本地系统账号,如图。

3.2 

Description:服务描述

DisplayName:服务名称

ServiceName:服务配置

StartType:服务启动类型,选择Automatic为开机自动启动

三、生成项目

右键重新生成项目,打开根目录,在\bin\Debug,下会生成相应程序。这时候需要手写一个安装文件和卸载文件,安装或是卸载时都需要用管理员模式运行。

1、安装文件Install.bat

%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe %~dp0\WinService.ReadLog.exe
Net Start mp.readlog
sc config mpreadlog start= auto
pause

2、卸载文件UnInstall.bat

Net stop mp.readlog
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe /u %~dp0\WinService.ReadLog.exe
pause

3、 查看services.msc

4、 查看日志

这篇关于.net framework 4.8 开发windows系统服务的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1117324

相关文章

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

sysmain服务可以禁用吗? 电脑sysmain服务关闭后的影响与操作指南

《sysmain服务可以禁用吗?电脑sysmain服务关闭后的影响与操作指南》在Windows系统中,SysMain服务(原名Superfetch)作为一个旨在提升系统性能的关键组件,一直备受用户关... 在使用 Windows 系统时,有时候真有点像在「开盲盒」。全新安装系统后的「默认设置」,往往并不尽编

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

基于Python实现自动化邮件发送系统的完整指南

《基于Python实现自动化邮件发送系统的完整指南》在现代软件开发和自动化流程中,邮件通知是一个常见且实用的功能,无论是用于发送报告、告警信息还是用户提醒,通过Python实现自动化的邮件发送功能都能... 目录一、前言:二、项目概述三、配置文件 `.env` 解析四、代码结构解析1. 导入模块2. 加载环

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

Nginx中配置使用非默认80端口进行服务的完整指南

《Nginx中配置使用非默认80端口进行服务的完整指南》在实际生产环境中,我们经常需要将Nginx配置在其他端口上运行,本文将详细介绍如何在Nginx中配置使用非默认端口进行服务,希望对大家有所帮助... 目录一、为什么需要使用非默认端口二、配置Nginx使用非默认端口的基本方法2.1 修改listen指令