zoukankan      html  css  js  c++  java
  • 如何用.NET创建Windows服务

    我们将研究如何创建一个作为Windows服务的应用程序。内容包含什么是Windows服务,如何创建、安装和调试它们。会用到System.ServiceProcess.ServiceBase命名空间的类。


    什么是Windows服务?


      Windows服务应用程序是一种需要长期运行的应用程序,它对于服务器环境特别适合。它没有用户界面,并且也不会产生任何可视输出。任何用户消息都会被写进Windows事件日志。计算机启动时,服务会自动开始运行。它们不要用户一定登录才运行,它们能在包括这个系统内的任何用户环境下运行。通过服务控制管理器,Windows服务是可控的,可以终止、暂停及当需要时启动。

      Windows 服务,以前的NT服务,都是被作为Windows NT操作系统的一部分引进来的。它们在Windows 9x及Windows Me下没有。你需要使用NT级别的操作系统来运行Windows服务,诸如:Windows NT、Windows 2000 Professional或Windows 2000 Server。举例而言,以Windows服务形式的产品有:Microsoft Exchange、SQL Server,还有别的如设置计算机时钟的Windows Time服务。


    创建一个Windows服务

      我们即将创建的这个服务除了演示什么也不做。服务被启动时会把一个条目信息登记到一个数据库当中来指明这个服务已经启动了。在服务运行期间,它会在指定的时间间隔内定期创建一个数据库项目记录。服务停止时会创建最后一条数据库记录。这个服务会自动向Windows应用程序日志当中登记下它成功启动或停止时的记录。

      Visual Studio .NET能够使创建一个Windows服务变成相当简单的一件事情。启动我们的演示服务程序的说明概述如下。

    1.     新建一个项目
    2. 从一个可用的项目模板列表当中选择Windows服务
    3. 设计器会以设计模式打开
    4. 从工具箱的组件表当中拖动一个Timer对象到这个设计表面上 (注意: 要确保是从组件列表而不是从Windows窗体列表当中使用Timer)
    5. 设置Timer属性,Enabled属性为False,Interval属性30000毫秒
    6. 切换到代码视图页(按F7或在视图菜单当中选择代码),然后为这个服务填加功能
    7.双击这个Timer,然后在里面(即:在事件private void timer1_Elapsed(object sender,
    System.Timers.ElapsedEventArgs e){}里面)写一些服务操作的代码


    Windows
    服务的构成

      在你类后面所包含的代码里,你会注意到你所创建的Windows服务扩充了System.ServiceProcess.Service类。所有以.NET方式建立的Windows服务必须扩充这个类。它会要求你的服务重载下面的方法,Visual Studio默认时包括了这些方法。

    • Dispose – 清除任何受控和不受控资源(managed and unmanaged resources)
    • OnStart – 控制服务启动
    • OnStop – 控制服务停止

    数据库表脚本样例

      在这个例子中使用的数据库表是使用下面的T-SQL脚本创建的。我选择SQL Server数据库。你可以很容易修改这个例子让它在Access或任何你所选择的别的数据库下运行。

    CREATE TABLE [dbo].[MyServiceLog] (
       [in_LogId] [
    int] IDENTITY (11) NOT NULL,
       [vc_Status] [nvarchar] (
    40
               COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
       [dt_Created] [datetime] NOT NULL
    ) ON [PRIMARY]



    Windows服务样例

      下面就是我命名为MyService的Windows服务的所有源代码。大多数源代码是由Visual Studio自动生成的。

    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.Diagnostics;
    using System.ServiceProcess;

    namespace CodeGuru.MyWindowsService




    安装Windows服务

      Windows服务不同于普通Windows应用程序。不可能简简单单地通过运行一个EXE就启动Windows服务了。安装一个Windows服务应该通过使用.NET Framework提供的InstallUtil.exe来完成,或者通过诸如一个Microsoft Installer (MSI)这样的文件部署项目完成。


    添加服务安装程序

      创建一个Windows服务,仅用InstallUtil程序去安装这个服务是不够的。你必须还要把一个服务安装程序添加到你的Windows服务当中,这样便于InstallUtil或是任何别的安装程序知道应用你服务的是怎样的配置设置。

    1. 将这个服务程序切换到设计视图
    2. 右击设计视图选择“添加安装程序”
    3. 切换到刚被添加的ProjectInstaller的设计视图
    4. 设置serviceInstaller1组件的属性:
        1) ServiceName = My Sample Service
        2) StartType = Automatic
    5. 设置serviceProcessInstaller1组件的属性
        1) Account = LocalSystem
    6. 生成解决方案

      在完成上面的几个步骤之后,会自动由Visual Studio产生下面的源代码,它包含于ProjectInstaller.cs这个源文件内

    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Configuration.Install;

    namespace CodeGuru.MyWindowsService
    {
      
    /// <summary>
      
    /// Summary description for ProjectInstaller.
      
    /// </summary>

      [RunInstaller(true)]
      
    public class ProjectInstaller : 
    System.Configuration.Install.Installer
      
    {
       
    private System.ServiceProcess.ServiceProcessInstaller 
    serviceProcessInstaller1;
       
    private System.ServiceProcess.ServiceInstaller serviceInstaller1;
       
    /// <summary>
       
    /// Required designer variable.
       
    /// </summary>

       private System.ComponentModel.Container components = null;

       
    public ProjectInstaller()
       
    {
         
    // This call is required by the Designer.
         InitializeComponent();

         
    // TODO: Add any initialization after the InitComponent call
       }


       
    Component Designer generated code
      }

    }





    用InstallUtil安装Windows服务

      现在这个服务已经生成,你需要把它安装好才能使用。下面操作会指导你安装你的新服务。

    1. 打开Visual Studio .NET命令提示
    2. 改变路径到你项目所在的bin"Debug文件夹位置(如果你以Release模式编译则在bin"Release文件夹)
    3. 执行命令“InstallUtil.exe MyWindowsService.exe”注册这个服务,使它建立一个合适的注册项。
    4. 右击桌面上“我的电脑”,选择“管理”就可以打计算机管理控制台
    5. 在“服务和应用程序”里面的“服务”部分里,你可以发现你的Windows服务已经包含在服务列表当中了
    6. 右击你的服务选择启动就可以启动你的服务了

      在每次需要修改Windows服务时,这就会要求你卸载和重新安装这个服务。不过要注意在卸载这个服务前,最好确保服务管理控制台已经关闭,这会是一个很好的习惯。如果没有这样操作的话,你可能在卸载和重安装Windows服务时会遇到麻烦。仅卸载服务的话,可以执行相的InstallUtil命令用于注销服务,不过要在后面加一个/u命令开关。


    调试Windows服务

      从另外的角度度看,调试Windows服务绝不同于一个普通的应用程序。调试Windows服务要求的步骤更多。服务不能象你对普通应用程序做的那样,只要简单地在开发环境下执行就可以调试了。服务必须首先被安装和启动,这一点在前面部分我们已经做到了。为了便于跟踪调试代码,一旦服务被启动,你就要用Visual Studio把运行的进程附加进来(attach)。记住,对你的Windows服务做的任何修改都要对这个服务进行卸载和重安装。


    附加正在运行的Windows服务

      为了调试程序,有些附加Windows服务的操作说明。这些操作假定你已经安装了这个Windows服务并且它正在运行。

    1. 用Visual Studio装载这个项目
    2. 点击“调试”菜单
    3. 点击“进程”菜单
    4. 确保 显示系统进程 被选
    5. 在 可用进程 列表中,把进程定位于你的可执行文件名称上点击选中它
    6. 点击 附加 按钮
    7. 点击 确定
    8. 点击 关闭
    9. 在timer1_Elapsed方法里设置一个断点,然后等它执行


    总结

      现在你应该对Windows服务是什么,以及如何创建、安装和调试它们有一个粗略的认识了。Windows服务的额处的功能你可以自行研究。这些功能包括暂停(OnPause)和恢复(OnContinue)的能力。暂停和恢复的能力在默认情况下没有被启用,要通过Windows服务属性来设置。


    --------------------
    另外
    一个较完整的例子:
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.ServiceProcess;
    using System.Data.SqlClient;
    //myself
    using TxXml;
    using MSXML2;
    using System.IO;
    using Microsoft.Win32;
    //using System.Threading;
    //using System.Text;
    using System.Windows.Forms;

    namespace WinService
    {
        
    public class Service1 : System.ServiceProcess.ServiceBase
        
    {
            
    private System.Timers.Timer timer1;
            
    private string reg_strHttp,reg_sqlServer,reg_database,reg_uid,reg_pwd,reg_timeout;
            
    private static string connString;
            
    /// <summary> 
            
    /// 必需的设计器变量。
            
    /// </summary>

            private System.ComponentModel.Container components = null;

            
    public Service1()
            
    {
                
    // 该调用是 Windows.Forms 组件设计器所必需的。
                InitializeComponent();

                
    // TODO: 在 InitComponent 调用后添加任何初始化
            }


            
    // 进程的主入口点
            static void Main()
            
    {
                System.ServiceProcess.ServiceBase[] ServicesToRun;
        
                
    // 同一进程中可以运行多个用户服务。若要将
                
    //另一个服务添加到此进程,请更改下行
                
    // 以创建另一个服务对象。例如,
                
    //
                
    //   ServicesToRun = New System.ServiceProcess.ServiceBase[] {new Service1(), new MySecondUserService()};
                
    //
                ServicesToRun = new System.ServiceProcess.ServiceBase[] new Service1() };

                System.ServiceProcess.ServiceBase.Run(ServicesToRun);
            }


            
    /// <summary> 
            
    /// 设计器支持所需的方法 - 不要使用代码编辑器 
            
    /// 修改此方法的内容。
            
    /// </summary>

            private void InitializeComponent()
            
    {
                
    this.timer1 = new System.Timers.Timer();
                ((System.ComponentModel.ISupportInitialize)(
    this.timer1)).BeginInit();
                
    // 
                
    // timer1
                
    // 
                this.timer1.Enabled = true;
                
    this.timer1.Interval = 60000;
                
    this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);
                
    // 
                
    // Service1
                
    // 
                this.ServiceName = "Service1";
                ((System.ComponentModel.ISupportInitialize)(
    this.timer1)).EndInit();

            }


            
    /// <summary>
            
    /// 清理所有正在使用的资源。
            
    /// </summary>

            protected override void Dispose( bool disposing )
            
    {
                
    if( disposing )
                
    {
                    
    if (components != null
                    
    {
                        components.Dispose();
                    }

                }

                
    base.Dispose( disposing );
            }


            
    /// <summary>
            
    /// 设置具体的操作,以便服务可以执行它的工作。
            
    /// </summary>

            protected override void OnStart(string[] args)
            
    {
                
    // TODO: 在此处添加代码以启动服务。
                this.timer1.Enabled = true
            }

     
            
    /// <summary>
            
    /// 停止此服务。
            
    /// </summary>

            protected override void OnStop()
            
    {
                
    // TODO: 在此处添加代码以执行停止服务所需的关闭操作。
            }


            
    //取全局参数
            protected void get_config()
            
    {
                
    //Thread.Sleep(9000);
                RegistryKey regkey;
                regkey
    =Registry.LocalMachine.OpenSubKey(@"SOFTWARE"SPACEN"xugang");        //读取注册表
                
                reg_strHttp 
    = regkey.GetValue("strHttp").ToString();           //接口址
                reg_sqlServer = regkey.GetValue("sqlServer").ToString();       //数据库服务名 
                reg_database = regkey.GetValue("database").ToString();         //数据库名
                reg_uid = regkey.GetValue("uid").ToString();                   //用户ID
                reg_pwd = regkey.GetValue("pwd").ToString();                   //密码
                reg_timeout = regkey.GetValue("timeout").ToString();           //超时时间

                
    //time1=time2=Convert.ToInt32(regkey.GetValue("time1").ToString());         //时间
            }


            
    private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            
    {
                
    if( connString ==null || connString =="")
                
    {
                    get_config();
                    connString 
    = "user id="+reg_uid+";password="+reg_pwd+";initial catalog="+reg_database+";";
                    connString 
    +="data source="+reg_sqlServer+"";
                }


                
                
    //在数据库查找用户设定更新时间
                string selectString="select str_DataTime from uptime";
                SqlConnection conn
    =new SqlConnection(connString); 
                
    //SqlCommand comm=new SqlCommand("insert into users (police_mark,pw,unit_number,purview) values('test','11','22','33')",conn); 
                SqlCommand comm=new SqlCommand(selectString,conn);
                conn.Open(); 
                
    string str_return = comm.ExecuteScalar().ToString(); 
                
    //conn.Close();
                
    //conn.Dispose();
                
    //comm.Dispose();

                
    //str_return = str_return.Substring(0,10);

                DateTime getTime 
    =(DateTime) Convert.ToDateTime(str_return); 
                DateTime dt 
    = DateTime.Now;
     
                
    if(getTime.Hour == dt.Hour && getTime.Minute == dt.Minute)  //用户设定时间 与 系统时间比较
                {
                    
    try
                    
    {
                        
    //DateTime dt = DateTime.Now;
                        string upDatetime = dt.ToString();
                        upDatetime 
    = upDatetime.Substring(0,10);
                        upDatetime 
    = upDatetime + ' '+"00:00:00";


                        
    //红名单表的提交
                        SqlDataAdapter redAdapter= new SqlDataAdapter("select carnumber,cartype,jdcfzjg from redlist where uptime>='"+upDatetime+"",connString);
                        DataSet redDataSet 
    = new DataSet();
                        redAdapter.Fill(redDataSet);
        
                        
    string str="";  //接口_返回值
                        XMLHTTP red_data = new XMLHTTPClass();

                        
    for(int i=0;i<redDataSet.Tables[0].Rows.Count;i++)
                        
    {
                            
    //向接口发送_红名单表的一条记录
                            
    //do
                            
    //{
                                str="";
                                
    string FilePath=reg_strHttp+"?hpzl="+redDataSet.Tables[0].Rows[i][1].ToString()+"&hphm="+redDataSet.Tables[0].Rows[i][0].ToString()+"&jdcfzjg="+redDataSet.Tables[0].Rows[i][2].ToString()+"&zt=redlist";
                                red_data.open(
    "post",FilePath,false,"","");            
                                red_data.setRequestHeader(
    "content-type","text/html; charset=gb2312");
                                red_data.send(
    "");
                                
    if(red_data.readyState==4)
                                
    {
                                    str
    =red_data.responseText;
                                }

                            
    //}
                            
    //while(str!="redOK");  //判断记录的返回
                            
                            
    ////////////////
                            //string connString = "user id="+reg_uid+";password="+reg_pwd+";initial catalog="+reg_database+";";
                            
    //connString +="data source="+reg_sqlServer+";Connect Timeout="+reg_timeout+"";
                
                            
    //在数据库查找用户设定更新时间
                            
    //string selectString="select str_DataTime from uptime";
                            
    //SqlConnection conn=new SqlConnection(connString); 
                            selectString = "";
                            
    if( str=="redOK")
                            
    {
                                selectString 
    = ("update redlist set mark='1'where carnumber='"+redDataSet.Tables[0].Rows[i][0].ToString()+"' and cartype='"+redDataSet.Tables[0].Rows[i][1].ToString()+"'");
                                comm.CommandText 
    = selectString;
                                comm.Connection 
    = conn;
                                
    if(conn.State == ConnectionState.Closed)conn.Open(); 
                                comm.ExecuteNonQuery(); 
                            }

                            
    ////////////////
                        }

                        
    //conn.Close();
                        
    //conn.Dispose();
                        
    //comm.Dispose();
                     
                        
    //白名单表的提交
                        SqlDataAdapter whiteAdapter= new SqlDataAdapter("select carnumber,cartype,jdcfzjg from whitelist where uptime>='"+upDatetime+"",connString);
                        DataSet whiteDataSet 
    = new DataSet();
                        whiteAdapter.Fill(whiteDataSet);
        
                        XMLHTTP white_data 
    = new XMLHTTPClass();
                        
                        
    for(int i=0;i<whiteDataSet.Tables[0].Rows.Count;i++)
                        
    {
                            
    //向接口发送_白名单表的一条记录
                            
    //do
                            
    //{
                                str="";
                                
    string FilePath=reg_strHttp+"?hpzl="+whiteDataSet.Tables[0].Rows[i][1].ToString()+"&hphm="+whiteDataSet.Tables[0].Rows[i][0].ToString()+"&jdcfzjg="+whiteDataSet.Tables[0].Rows[i][2].ToString()+"&zt=whitelist";
                                white_data.open(
    "post",FilePath,false,"","");            
                                white_data.setRequestHeader(
    "content-type","text/html; charset=gb2312");
                                white_data.send(
    "");
                                
    if(white_data.readyState==4)
                                
    {
                                    str
    =white_data.responseText;
                                }

                            
    //}
                            
    //while(str!="whiteOK");  //判断记录的返回
                            selectString = "";
                            
    if( str=="whiteOK")
                            
    {
                                selectString 
    = ("update whitelist set mark='1'where carnumber='"+redDataSet.Tables[0].Rows[i][0].ToString()+"' and cartype='"+redDataSet.Tables[0].Rows[i][1].ToString()+"'");
                                comm.CommandText 
    = selectString;
                                comm.Connection 
    = conn;
                                
    if(conn.State == ConnectionState.Closed)conn.Open(); 
                                comm.ExecuteNonQuery(); 
                            }

                        }

                        conn.Close();
                        conn.Dispose();
                        comm.Dispose();
                        
                    }

                    
    catch(Exception ex)
                    
    {
                        MessageBox.Show(
    "告知数据服务更新错误,"+"每天自动上传失败!"+ex.Message,"警告",MessageBoxButtons.OK,MessageBoxIcon.Warning,MessageBoxDefaultButton.Button1, 
                        MessageBoxOptions.DefaultDesktopOnly); 
                        
                        conn.Close();
                        conn.Dispose();
                        comm.Dispose();
                    }


                }

                
    //else
                
    //{
                   
                
    //}
            
                
    //SqlConnection conn=new SqlConnection(connString); 
                
    //SqlCommand comm=new SqlCommand("insert into users (police_mark,pw,unit_number,purview) values('test','11','22','33')",conn); 
                
    //SqlCommand comm=new SqlCommand(selectString,conn);
                
    //conn.Open(); 
                
    //comm.ExecuteNonQuery(); 
                
    //conn.Close(); 
            }

            
        }

    }


    卸载:sc delete 服务名

    参考文章:
    (转)如何实现Windows服务

  • 相关阅读:
    使用logstash迁移ES1.x数据到ES6.x
    Kafka版本升级
    linux配置Mariadb双主互备
    OS7误删yum
    python中运行js代码 js2py
    python获取js里window对象
    python使用execjs执行js
    .Net Core AddTransient、AddScoped和AddSingleton的使用
    查询SQL Server数据库应用程序访问等待执行的SQL
    Spring Boot 2.4.0 发布说明
  • 原文地址:https://www.cnblogs.com/greatandforever/p/1238270.html
Copyright © 2011-2022 走看看