.net framework 4.8 开发windows系统服务

news2024/11/15 2:08:51

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;//成功数
                //循环excel
                for (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_READDATA
                            DbHelper.Db.Insertable(main).ExecuteCommand();
                        }
                        else
                        {
                            main = fileModel;
                            main.ROW_NO = lastNum;
                            main.UPDATE_DATE = DateTime.Now;
                            //4.1同步表SYNC_READDATA
                            DbHelper.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_REC
                        DbHelper.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_RES
                        DbHelper.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_STATISTICS
                            DbHelper.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_STATISTICS
                            DbHelper.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、 查看日志

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2082115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp video标签无法播放视频

当video标签路径含有中文以及特殊字符视频就会无法播放 解决方法使用encodeURIComponent对路径进行加密处理 videoSrc data.coursewareFile? ${appConfig.apiUrl encodeURIComponent(data.coursewareFile)}: "";最后效果

GHA高质量seo文章怎么写?

撰写高质量SEO文章不仅仅是文字的堆砌&#xff0c;更是对内容的精心打磨&#xff0c;而GHA文章更是如此&#xff0c;想写出一篇GHA文章&#xff0c;首先就要保证以下几点&#xff0c;一定要原创&#xff0c;谷歌对于原创内容是极其看重的&#xff0c;哪怕是伪原创&#xff0c;在…

一种导出PPT到MP4的方法

需求 导出PPT到MP4&#xff0c;并记录每页&#xff0c;每个动作的时间线。通过 MP4时间线 就可以在页面上很方便的放映PPT的内容&#xff0c;并支持翻页点击。 代码 保存每一页的图像信息&#xff0c;用做播放器的缩略图 public void SaveThumbnail(string ppt_filepath, st…

【STL】红黑树的全面探索与红黑树的实现

ps&#xff1a;文章最后有完整的代码 1.红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路…

如何使用IDEA搭建Mybatis框架环境

文章目录 ☕前言为什么学习框架技术Mybatis框架简介 &#x1f379;一、如何配置Mybatis框架环境1.1下载需要MyBatis的jar文件1.2部署jar文件1.3创建MyBatis核心配置文件configuration.xml1.4.创建持久类(POJO)和SQL映射文件1.5.创建测试类 &#x1f9cb;二、 MyBatis框架的优缺…

前端性能优化:使用Vue3+TS+Canvas对图片进行压缩后再上传,优化带宽,减小服务器存储成本,减少流量损耗

在上传图片之前&#xff0c;对图片进行压缩。看到这里是不是有点懵&#xff0c;前端怎么压缩图片呢&#xff0c;这不应该是后端做的吗&#xff1f; 但是我在开发的时候接到了这样一个需求&#xff0c;要求对用户上传的图片进行一定的压缩&#xff0c;而且并且尽量还原图片的清…

大模型如何改变世界?李彦宏:未来至少一半人要学会“提问题“

2023年爆火的大模型&#xff0c;对我们来说意味着什么&#xff1f; 百度创始人、董事长兼CEO李彦宏认为&#xff0c;“大模型即将改变世界。” 5月26日&#xff0c;李彦宏参加了在北京举办的2023中关村论坛&#xff0c;发表了题为《大模型改变世界》的演讲。李彦宏认为&#…

2024年新算法-基于SBOA-BP混合神经网络的数据预测(Python代码实现)

在今天的数字化时代&#xff0c;机器学习和人工智能领域的不断发展为数据处理和预测提供了强大的工具。其中&#xff0c;BP神经网络&#xff08;反向传播神经网络&#xff09;作为一种经典的网络模型&#xff0c;因其能够处理复杂的非线性问题而备受关注。然而&#xff0c;传统…

吴恩达机器学习课后作业-07kmeans and pca

k-均值与PCA k-均值图片颜色聚类 PCA&#xff08;主成分分析&#xff09;对x去均值化图像降维 k-均值 K-均值是最普及的聚类算法&#xff0c;算法接受一个未标记的数据集&#xff0c;然后将数据聚类成不同的组。 K-均值是一个迭代算法&#xff0c;假设我们想要将数据聚类成n个…

python-变量声明、数据类型、标识符

一.变量 1.什么是变量 为什么需要变量呢&#xff1f; 一个程序就是一个世界&#xff0c;不论使用哪种高级程序语言编写代码&#xff0c;变量都是其程序的基本组成单位。如下图所示的sum和sub都是变量。 变量的定义&#xff1a; 变量相当于内存中一个数据存储空间的表示&#…

Spring MVC常用注解及用法

目录 1.建立连接--RequestMapping 2.请求 2.1 传递单个参数 2.2 传递多个参数 2.3 传递对象 2.4 参数重命名--RequestParam 2.5 传递数组 2.6 传递集合 2.7 传递json数据--RequestBody 2.8 获取URL中参数--PathVariable 2.9 上传文件--RequestPart 2.10 获取Cookie--…

bomb 实验

GDB常用命令&#xff1a; GDB调试常用命令-CSDN博客 原理&#xff1a; 编译与反汇编过程-CSDN博客 Bomb实验实现 阶段一&#xff1a; 分析 分配空间&#xff1a;sub $0x8,%rsp 为局部变量分配栈空间。设置参数&#xff1a;mov $0x402400,%esi 将字符串地址加载到 %esi。…

MMsegmentation与MMdeploy简单使用

最近涉及到了图像分割的任务&#xff0c;于是拿来写下博客加深下使用。 MMsegmentation与MMdeploy的环境配置暂不做讲解&#xff0c;在官网和其他博客中有很多说明。 MMdeploy主要是把pt转为 onnx_int8的情况。 MMsegmentation环境配置可以参考 : 安装与配置MMSegmentation 目录…

【管理型文档】软件需求管理过程(原件)

软件需求管理规程应明确需求收集、分析、确认、变更控制及验证等流程&#xff0c;确保需求准确反映用户期望&#xff0c;支撑软件开发。该规程要求系统记录需求来源&#xff0c;通过评审确保需求完整、清晰、无歧义&#xff0c;实施变更控制以维护需求基线稳定&#xff0c;并持…

后端面试真题整理

面试问题整理 本人主要记录2024年秋招、春招过程中的疑难八股真题&#xff0c;参考来源&#xff1a;牛客网、知乎等。 八股 深拷贝与浅拷贝 浅拷贝&#xff1a; 浅拷贝会在堆上创建一个新的对象&#xff08;区别于引用拷贝的一点&#xff09;&#xff0c;不过&#xff0c;如果…

井盖丢失隐患大?智慧井盖监管系统帮你解决

在现代都市中&#xff0c;我们每天行走在钢筋水泥之间&#xff0c;却很少有人注意到脚下的小小井盖。这些不起眼的圆形铁盘不仅是城市地下管网的入口&#xff0c;更是维系城市生命线的重要组成部分。然而&#xff0c;当暴雨来袭&#xff0c;或是深夜无人之时&#xff0c;井盖的…

无线麦克风什么牌子的音质效果好?一文读懂麦克风哪个牌子的好

无线领夹麦克风哪款音质最好&#xff1f;在这个追求高质量音效的年代&#xff0c;选择一款合适的无线领夹麦克风&#xff08;简称领夹麦&#xff09;对于提升录音或直播的音质至关重要。随着市场的不断扩大&#xff0c;市面上充斥着大量信号不稳定、音质差的无线领夹麦克风&…

2024年汽车零部件企业CRM研究:服务商排名、案例分析、需求分析

最近媒体上频现各车企大佬发声&#xff0c;抗议某汽车企业“不要卷价格&#xff0c;要卷长期价值”&#xff0c;还有的直接批判其打破行业规则。图穷匕现&#xff0c;汽车行业的竞争愈发激烈了。 汽车产业作为我国国民经济的重要支柱产业、经济增长和转型的重要抓手&#xff0…

微软将持续多年的 Mono 项目移交给 Wine

今天&#xff0c;微软突然决定将 Mono 项目交由 Wine 开发社区管理。自Mono项目上一次作为开源.NET框架发布以来&#xff0c;已经过去了五年时间&#xff0c;此前Wine已经使用了Mono的代码&#xff0c;而在微软专注于开源.NET和其他工作的情况下&#xff0c;此举是合理的&#…

Python编程的终极十大工具(非常详细)零基础入门到精通,收藏这一篇就够了

&#x1f91f; 基于入门网络安全打造的&#xff1a;&#x1f449;黑客&网络安全入门&进阶学习资源包 Python一直以来都是程序员们的首选编程语言之一&#xff0c;其灵活性和功能强大的库使其成为解决各种问题的理想选择。在本文中&#xff0c;我们将介绍Python编程的终…