c#创建windows service示例

    技术2022-05-20  35

    一、windows service示例使用的业务环境之所以先介绍windows service示例使用的业务环境,是因为如果有这些介绍,后面理解起来更加容易。我在本文中所举的windows service示例,源于我们实际工作中一个web项目的需要,该项目是一个在线考试系统,其中有这么一个取舍,在线考试的时候,因为考生数量较多,为避免交卷时将答题信息一股脑儿往数据库里插入出错,采取了这样一种办法:先让所有的考生交卷,交卷的时候并不往数据库里插入数据,而是将考生答题情况生成一个xml文件,在考生交卷后上传到服务器固定的目录下,然后由程序去解析xml文件,抽取数据,插入到数据库。为了减轻服务器的压力,这些上传到服务器上的xml文件解析工作不能在考生考试时候进行,这样做是尽量减少考生考试时出错的几率。那么,如何对这些上传到服务器上的xml文件来解析,什么时间来解析,是必须要考虑的。如果不考虑这些,可以在考生交卷将包含答题信息的xml文件上传到服务器之后,由web系统直接执行一段代码,对固定目录下提交的xml文件扫描,读取数据并插入数据库。这也不失为一个好的办法。但如果想要在服务器压力较小的情况下再来对这些xml文件进行解析,参考网上的评论,据说有三个较好的办法:一是采用数据库的作业;二是采用windows的计划任务;三是采用windows service。不管怎么样,我最后决定采用windows service了。二、windows service示例实现的功能本文中的windows service示例,要实现代功能简单明确:1,定时扫描服务器固定目录下的xml格式文件;2,定时扫描固定目录下的xml文件,如果时间在晚上20到23点之间,提取xml文件中的数据,往本地数据库kaoshi中的表t_datiqk中插入数据;3,如果数据提取并插入成功,固定目录下的xml文件删除。三、用c#在vs2005中创建windows service的步骤前面介绍了很多本文中的windows service示例的情况,估计各位看官已经非常不耐烦了。那么好,现在进入真刀真枪的代码编写和操作步骤阶段。感谢微软,感谢vs2005,让我创建windows service如此的容易、快捷。接下来介绍在vs2005中用c#创建windows servcie的步骤。1、创建windows service工程项目打开vs2005,点击File-New-Project(偶用的是TeamSuit版VisioStudio),选择Windows Service。如下图。

    在工程名称输入框中,输入GradeService(这个是windows service的名字,你爱怎么取随你,俺管不着),然后在下面选择项目的保存路径,点击OK即可,在解决方案浏览器中可以看到,vs2005已经自动为你生成了一些必要的文件,如下图

    。将vs2005切换到属性浏览页面,Service1.cs会有以下属性:Autolog                                    是否自动写入系统的日志文件CanHandlePowerEvent       服务时候接受电源事件CanPauseAndContinue      服务是否接受暂停或继续运行的请求CanShutdown                       服务是否在运行它的计算机关闭时收到通知,以便能够调用 OnShutDown 过程CanStop                                 服务是否接受停止运行的请求ServiceName                        服务名系统默认产生的文件名让我很不爽,我决定要改掉它。于是我右键单击“Service1.cs”,改为“GradeService”,如下图。

    vs2005弹出一个窗口,如图,点击“是”。

    2、完善windows service功能,增加业务代码因为要记录日志,所以从工具栏的“Components”拖一个EventLog过来。另外,因为要定时执行,所以还需要一个计时器。从网上可以知道,有三种计时器。一种是System.Timers.Timer;一种是System.Threading.Timer;一种是System.Windows.Forms.Timer。大家都说用System.Timers.Timer好,没办法,那就用System.Timers.Timer吧。不过这个在设计页面上是看不到的,只有在GradeService.Designer.cs里面才可以看到它的声明。双击GradeService.cs[Design]页面,进入到代码页面。里面有两个空的函数,一个是OnStart,一个是OnStop。顾名思义,OnStart函数是服务启动时执行,OnStop函数在服务停止时执行。下面是GradeService.cs的具体代码using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Diagnostics;using System.ServiceProcess;using System.Text;using System.IO;using System.Web;using System.Data.SqlClient;using System.Configuration;

    namespace GradeService{    public partial class GradeService : ServiceBase    {        public GradeService()        {            InitializeComponent();            // 如果系统时间查看器中没有“Xml文件解析”这样的类别,就添加一个            if (!System.Diagnostics.EventLog.Exists("Xml文件解析"))            {                System.Diagnostics.EventLog.CreateEventSource("Xml文件解析服务", "Xml文件解析");            }            // 设置日志的名字            this.eventLog.Log = "Xml文件解析";            // 设置日志的来源            this.eventLog.Source = "Xml文件解析服务";        }        /// <summary>        /// 服务启动        /// </summary>        /// <param name="args"></param>        protected override void OnStart(string[] args)        {            // TODO: Add code here to start your service.            if (this.timer == null)            {                eventLog.WriteEntry("xml文件解析服务启动");                timer = new System.Timers.Timer();                // 每隔5分钟执行                this.timer.Interval = 5 * 60 * 1000;                // 设置timer可以激发Elapsed事件                this.timer.Enabled = true;                // 开始                this.timer.Start();                this.timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);            }        }        /// <summary>        /// 时间间隔到达后执行的代码        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)        {            // 停止计时            this.timer.Stop();            // 取系统当前时间            DateTime now = DateTime.Now;            // 判断当前时间是否在20到23点之间,如果是则执行业务代码,否则不执行            if (now.Hour <= 23 && now.Hour >= 20)            {                // 获取App.config文件中xml文件保存路径                string _basePath = System.Configuration.ConfigurationSettings.AppSettings["FilePath"];                // 开始扫描文件                this.ScanFile(_basePath);            }            // 开始计时            this.timer.Start();        }        /// <summary>        /// 服务停止        /// </summary>        protected override void OnStop()        {            // TODO: Add code here to perform any tear-down necessary to stop your service.            if (this.timer != null)            {                this.timer.Enabled = false;                this.timer.Stop();                this.timer.Dispose();                eventLog.WriteEntry("xml文件解析服务停止");            }        }        /// <summary>        /// 解析文件并将数据插入数据库        /// </summary>        /// <param name="fileName">文件全路径</param>        /// <param name="name">文件名</param>        private void InsertData(string fileName, string name)        {            // 读取xml文件内容            DataSet ds = new DataSet();            ds.ReadXml(fileName);            // 循环数据集并插入内容,采用事务            string msg = "解析文件" + name + "成功!";            // 获取连接数据库字符串            string sqlConnString = System.Configuration.ConfigurationSettings.AppSettings

    ["SqlConnString"];            if (sqlConnString == null)            {                eventLog.WriteEntry("在App.config文件中没有找到连接数据库的字符串,解析文件中止!");                return;            }            // 建立数据库连接            SqlConnection conn = new SqlConnection(sqlConnString);            try            {                conn.Open();            }            catch(Exception e)            {                // 如果连接失败,记录原因                eventLog.WriteEntry(e.Message);                return;            }            // 开始事务            SqlTransaction tran = conn.BeginTransaction();            SqlCommand comm = new SqlCommand();

                comm.Transaction = tran;            comm.Connection = conn;            try            {                // 从xml文件名中获取准考证和试卷编号                string temp = name.Substring(0, name.Length - 4);                string[] tempXmlName = temp.Split('-');                // 准考证号码                string c_zhunkaozhm = tempXmlName[0].ToString();                // 试卷编号                string c_shijuanbh = tempXmlName[3].ToString();                // Sql语句                string strSqlInsert = "INSERT INTO t_datiqk

    (c_zhunkaozhm,c_shijuanbh,c_timubh,c_timulx,c_fenzhi,c_geshilx,c_wentims,c_daan,c_huidada,c_datisj,c_zhe

    ngque) VALUES

    (@c_zhunkaozhm,@c_shijuanbh,@c_timubh,@c_timulx,@c_fenzhi,@c_geshilx,@c_wentims,@c_daan,@c_huidada,@c_da

    tisj,@c_zhengque)";                // Sql参数                SqlParameter param;                // 循环xml文件中抽取出来的数据                for (int i = 0; i < ds.Tables[0].Rows.Count; i++)                {                    comm.Parameters.Clear();                    comm.CommandText = strSqlInsert;// Sql语句

                        param = new SqlParameter("@c_zhunkaozhm", SqlDbType.VarChar);// 准考证号                    param.Value = c_zhunkaozhm;                    comm.Parameters.Add(param);

                        param = new SqlParameter("@c_shijuanbh", SqlDbType.VarChar);// 试卷编号                    param.Value = c_shijuanbh;                    comm.Parameters.Add(param);

                        param = new SqlParameter("@c_timubh", SqlDbType.VarChar);// 题目编号                    param.Value = ds.Tables[0].Rows[i]["c_bianhao"].ToString();                    comm.Parameters.Add(param);

                        param = new SqlParameter("@c_timulx", SqlDbType.Int);// 题目类型                    param.Value = Convert.ToInt32(ds.Tables[0].Rows[i]["c_timulx"]);                    comm.Parameters.Add(param);

                        param = new SqlParameter("@c_fenzhi", SqlDbType.Float);// 分值                    param.Value = Convert.ToSingle(ds.Tables[0].Rows[i]["c_fenzhi"]);                    comm.Parameters.Add(param);

                        param = new SqlParameter("@c_geshilx", SqlDbType.Int);// 格式类型                    param.Value = Convert.ToInt32(ds.Tables[0].Rows[i]["c_geshilx"]);                    comm.Parameters.Add(param);

                        param = new SqlParameter("@c_wentims", SqlDbType.VarChar);// 问题描述                    param.Value = ds.Tables[0].Rows[i]["c_wentims"].ToString();                    comm.Parameters.Add(param);

                        param = new SqlParameter("@c_daan", SqlDbType.Int);// 正确答案                    param.Value = Convert.ToInt32(ds.Tables[0].Rows[i]["c_zhengqueda"]);                    comm.Parameters.Add(param);

                        param = new SqlParameter("@c_huidada", SqlDbType.Int);// 考生回答答案                    param.Value = Convert.ToInt32(ds.Tables[0].Rows[i]["c_daan"]);                    comm.Parameters.Add(param);

                        param = new SqlParameter("@c_datisj", SqlDbType.DateTime);// 答题时间                    param.Value = Convert.ToDateTime(ds.Tables[0].Rows[i]["c_datisj"]);                    comm.Parameters.Add(param);

                        param = new SqlParameter("@c_zhengque", SqlDbType.Int);// 是否正确                    param.Value = Convert.ToInt32(ds.Tables[0].Rows[i]["c_zhengque"]);                    comm.Parameters.Add(param);

                        comm.ExecuteNonQuery();// 执行更新                }                tran.Commit();                // 扫描成功后删除xml文件                if (File.Exists(fileName))                {                    File.Delete(fileName);                }            }            catch (Exception ex)            {                // 会滚sql操作                tran.Rollback();                // 获取异常信息                msg = ex.Message;            }            finally            {                conn.Close();            }            // 将操作信息或异常信息写入日志(日志可以在系统的事件查看器中看到)            eventLog.WriteEntry(msg);        }        /// <summary>        /// 循环扫描具体路径下的文件        /// </summary>        /// <param name="filePath"></param>        private void ScanFile(string filePath)        {            // 创建DirectoryInfo实例            DirectoryInfo dirInfo = new DirectoryInfo(filePath);            // 得到源目录的文件列表            FileInfo[] files = dirInfo.GetFiles();            // 循环解析文件            for (int i = 0; i < files.Length; i++)            {                // 判断文件的后缀是否为xml                 string postFix = files[i].Extension;                // 获取全路径                string fileNme = files[i].FullName;                // 获取文件名                string name = files[i].Name;                if (postFix == ".xml")                {                    this.InsertData(fileNme, name);                }            }        }    }}3、将安装程序添加到服务应用程序想要把windows service安装起来,不是双击GradeService.exe就可以的,它和普通的可执行文件安装办法不一样。

    首先,我们要给windows service添加Installer。右键点击设计视图,选择Add Installer,VS将会为我们添加ProjectInstaller.cs,并在ProjectInstaller中添加组件serviceInstaller1和serviceProcessInstaller1,现在我们来修改他们的属性来控制Service的安装和启动选项。在ProjectInstaller得设计视图中选中serviceProcessInstaller1,将它得Account属性选为LocalSystem,这样以这个帐号服务启动。如果你希望系统启动时自动启动服务得话,将serviceInstaller1的StartType的属性选为Automatic,如果手动启动的话,选为manaul。其次,要安装service,我们要用到IntallUtil.exe这个程序,这个程序位于C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727.点击开始菜单,选择“运行”,在运行对话框中输入cmd,进入到命令行窗口,输入cd :/WINDOWS/Microsoft.NET/Framework/v2.0.50727,进入到这个目录,然后输入installutil F:/project/考试系统/项目代码/Service/GradeService/GradeService/bin/Debug/GradeService.exe, installutil后边的内容就是我们的工程生成的可执行程序的路径,可以根据你自己的实际情况进行修改。

    如果你给ServiceInstaller1的StartType设为Automatic的话,安装完服务,服务已经运行起来了,如果StartType是Manual的话,你需要手动启动。现在我们进入“服务”,要打开“服务”,请单击“开始”,指向“设置”,然后单击“控制面板”。依次单击“性能和维护”、“管理工具”,然后双击“服务”。在里边你应该能够看到我们制作的Service GradeService。在这里边,我们可以启动,关闭服务,还可以设置服务的启动类型。然后,我们看看服务有没有正确的写入日志,我们需要进入到事件查看器,要打开“事件查看器”,请单击“开始”,指向“设置”,然后单击“控制面板”。单击“性能和维护”,单击“管理工具”,然后双击“事件查看器”。如下图所示,我们的消息已经成功的写到了系统日志里了,下图。

    四、在使用windows service过程中发现的小问题在使用windows service中,因为有一些变量,不想写死,想保存在配置文件中,于是给示例service加了一个配置文件,叫App.config。其中定义了一些key,比如<add key="SqlConnString" value="Data Source=(local);Database=kaoshi;User ID=sa;Password=780910;"/>。但是发现,如果服务已经安装好后,去修改App.config中的key值,对服务并没有影响,windows servcie仍然按照App.config文件修改前的key值运行。不知道其他兄弟姐妹有没有遇到这种情况。

    五、在asp.net中如何控制自己创建的windows service(网上流传,尚未验证是否属实)windows service是可以在asp.net中进行控制的,你可以在asp.net构建的web项目中对服务器的windows service进行控制。但是要有两个前提。1、在web项目解决方案资源管理器中添加引用System.ServiceProcess.dll;然后在.cs中using System.ServiceProcess;然后在事件中写代码:   ServiceController sc=new ServiceController("GradeServiceContrller");// 建立服务控制类对象   if(sc.Status==ServiceControllerStatus.Stopped)   {    sc.Start();// 开始服务   }2、在web.config中模拟一个管理员用户。如admin(属于administrator组.)如下所示:<configuration>      <system.web>    <identity impersonate="true" userName="admin" password="admin" /> </system.web>

    </configuration>

    转自:http://dreambuild.blog.sohu.com/132659489.html


    最新回复(0)