Windows服务作用:定时用户消息推送,WEB程序实时统计等
Windows服务创建:C#创建服务的方式也有很多种,建议大家在做之前可以先全面了解一下这方面东西再去动手这样便于解决中间遇到一些比较棘手的小问题。
主要说一种通过SC命令实现服务的创建、修改、查询、卸载、开始、暂停,具体服务工作的业务可以另行完善。
1,创建一个控制台程序,当然也可以写个winform或者其他XXX
2,在创建好的项目中新建一个服务
创建完服务,剩下的就需要代码实现了。
思路:我们将通过模拟在命令窗中输入SC服务命令创建和操作服务,所以这里先把一些公用的方法写出来。
运行命令并返回命令输出消息
/// <summary> /// 运行CMD命令 /// </summary> /// <param name="cmd">命令</param> /// <returns></returns> public static string Cmd(string[] cmd) { Process p = new Process(); p.StartInfo.FileName = "cmd.exe"; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardInput = true; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; p.StartInfo.CreateNoWindow = true; p.Start(); p.StandardInput.AutoFlush = true; for (int i = 0; i < cmd.Length; i++) { p.StandardInput.WriteLine(cmd[i].ToString()); } p.StandardInput.WriteLine("exit"); string strRst = p.StandardOutput.ReadToEnd(); p.WaitForExit(); p.Close(); CloseProcess("cmd.exe");//执行结束,关闭cmd进程 return strRst; }
结束Process 方法
/// <summary> /// 关闭进程 /// </summary> /// <param name="ProcName">进程名称</param> /// <returns></returns> public static bool CloseProcess(string ProcName) { bool result = false; System.Collections.ArrayList procList = new System.Collections.ArrayList(); string tempName = ""; int begpos; int endpos; foreach (System.Diagnostics.Process thisProc in System.Diagnostics.Process.GetProcesses()) { tempName = thisProc.ToString(); begpos = tempName.IndexOf("(") + 1; endpos = tempName.IndexOf(")"); tempName = tempName.Substring(begpos, endpos - begpos); procList.Add(tempName); if (tempName == ProcName) { if (!thisProc.CloseMainWindow()) thisProc.Kill(); // 当发送关闭窗口命令无效时强行结束进程 result = true; } } return result; }
因为服务的请求可能会从系统服务或者应用程序发起请求,所以我们要加一个完善的主方法请求判断,如果是命令行过来的就给用户提供可选的操作菜单,否则运行服务。
定义一个枚举,记录不同请求来源。
/// <summary> /// 定义程序被启用的几种形式 /// </summary> public enum appModel { /// <summary> /// 网页启用 /// </summary> Web, /// <summary> /// 系统服务启用 /// </summary> Service, /// <summary> /// 窗体程序启用 /// </summary> Windows, /// <summary> /// 控制台启用 /// </summary> Console }
主方法内添加状态判断
static void Main(string[] args) { appModel mode = AutoDetectAppType();//获取应用程序请求来源 if (mode.Equals(appModel.Console)) {//如果是控制台程序,验证是否对服务操作 Console.WriteLine("选择金销帮后台服务操作"); Console.WriteLine("如需操作请选择,[0]服务状态查询[1]安装服务 [2]卸载服务 [3]启动服务[4]停止服务[5]退出"); var rs = int.Parse(Console.ReadLine()); DoParameter(rs); } else if (mode.Equals(appModel.Service)) { //如果是服务,运行系统服务 ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new MainServer(), }; ServiceBase.Run(ServicesToRun); } }
根据用户每次选择不同的菜单对Windows服务发出命令
/// <summary> /// 判断用户输入参数 /// </summary> /// <param name="rs">控制台输入参数</param> public static void DoParameter(int rs) { //[0]服务状态查询[1]安装服务 [2]卸载服务 [3]启动服务[4]停止服务[5]退出 switch (rs) { case 0: //查询 string back_query = Cmd(new string[] { "sc query jinxiaobangServices" });//查询服务信息 Console.WriteLine("------------------------------------------------------------------------------------"); Console.WriteLine("查询服务信息如下: " + back_query);//输出查询结果 Console.WriteLine("如需操作请选择,[0]服务状态查询[1]安装服务 [2]卸载服务 [3]启动服务[4]停止服务[5]退出"); Console.WriteLine("------------------------------------------------------------------------------------"); var param_query = int.Parse(Console.ReadLine()); DoParameter(param_query); break; case 1: //安装服务 var path = Process.GetCurrentProcess().MainModule.FileName; string back_create = Cmd(new string[] { "sc create jinxiaobangServices binpath= "" + path + "" displayName= JXBServices start= auto obj= localsystem ", "sc description "jinxiaobangServices" "金销帮后台异步通知、数据统计、定时任务等处理" " }); Console.WriteLine("------------------------------------------------------------------------------------"); Console.WriteLine("安装成功 " + back_create); Console.WriteLine("如需操作请选择,[0]服务状态查询[1]安装服务 [2]卸载服务 [3]启动服务[4]停止服务[5]退出"); Console.WriteLine("------------------------------------------------------------------------------------"); var param_create = int.Parse(Console.ReadLine()); DoParameter(param_create); break; case 2: //卸载服务 string back_delete = Cmd(new string[] { "sc delete jinxiaobangServices" });//卸载服务 Console.WriteLine("------------------------------------------------------------------------------------"); Console.WriteLine("卸载成功 " + back_delete); Console.WriteLine("如需操作请选择,[0]服务状态查询[1]安装服务 [2]卸载服务 [3]启动服务[4]停止服务[5]退出"); Console.WriteLine("------------------------------------------------------------------------------------"); var param_delete = int.Parse(Console.ReadLine()); DoParameter(param_delete); break; case 3: //启动服务 //Process.Start("sc", "start jinxiaobangServices");//sc执行命令 string back_start = Cmd(new string[] { "sc start jinxiaobangServices" });//启动服务 Console.WriteLine("------------------------------------------------------------------------------------"); Console.WriteLine("启动成功 " + back_start); Console.WriteLine("如需操作请选择,[0]服务状态查询[1]安装服务 [2]卸载服务 [3]启动服务[4]停止服务[5]退出"); Console.WriteLine("------------------------------------------------------------------------------------"); var param_start = int.Parse(Console.ReadLine()); DoParameter(param_start); break; case 4: //停止服务 string back_stop = Cmd(new string[] { "sc stop jinxiaobangServices" });//停止服务 Console.WriteLine("------------------------------------------------------------------------------------"); Console.WriteLine("停止服务 " + back_stop); Console.WriteLine("如需操作请选择,[0]服务状态查询[1]安装服务 [2]卸载服务 [3]启动服务[4]停止服务[5]退出"); Console.WriteLine("------------------------------------------------------------------------------------"); var param_stop = int.Parse(Console.ReadLine()); DoParameter(param_stop); //退出 break; case 5: //退出 break; } }
到这里就把整个服务操作过程了解清楚了,后面就可以准备自己的业务代码。例如服务启动时和停止时分别做一些业务操作
protected override void OnStart(string[] args) { // TODO: 在此处添加代码以启动服务。 FileStream fs = new FileStream(@"C:WindowsJinXBWinServer.log", FileMode.OpenOrCreate, FileAccess.Write); StreamWriter sw = new StreamWriter(fs); sw.BaseStream.Seek(0, SeekOrigin.End); sw.WriteLine("WindowsService: Service Started" + DateTime.Now.ToString() + " "); sw.Flush(); sw.Close(); fs.Close(); } protected override void OnStop() { // TODO: 在此处添加代码以执行停止服务所需的关闭操作。 FileStream fs = new FileStream(@"C:WindowsJinXBWinServer.log", FileMode.OpenOrCreate, FileAccess.Write); StreamWriter sw = new StreamWriter(fs); sw.BaseStream.Seek(0, SeekOrigin.End); sw.WriteLine("WindowsService: Service Stopped" + DateTime.Now.ToString() + " "); sw.Flush(); sw.Close(); fs.Close(); }
可以分别通过OnStart和OnStop去记录一下服务操作记录,来做个测试。
服务编写完,先别急着F5测试。因为运行权限的问题,这时可能会出现1053:服务没有及时响应启动或控制请求。这是因为VS权限不足,可以在debug文件中用管理员运行测试一下,是不是OK了。
特别注意:每次更新安装都要用最新的SetUp.exe安装包,点击右键生成可以自动在“SetUpExpressSingleImageDiskImagesDISK1setup.exe”路径下生成exe安装文件,一定记得安装最新版。
InstallShield Limited Edition for Visual Studio的具体使用,可以网上找一下,也可以参考这里:http://blog.csdn.net/kingmax54212008/article/details/44303539