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("查詢服務信息如下:\n\n\n " + 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("安裝成功\n\n\n" + 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("卸載成功\n\n\n" + 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("啟動成功\n\n\n" + 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("停止服務\n\n\n" + 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:\Windows\JinXBWinServer.log", FileMode.OpenOrCreate, FileAccess.Write); StreamWriter sw = new StreamWriter(fs); sw.BaseStream.Seek(0, SeekOrigin.End); sw.WriteLine("WindowsService: Service Started" + DateTime.Now.ToString() + "\n"); sw.Flush(); sw.Close(); fs.Close(); } protected override void OnStop() { // TODO: 在此處添加代碼以執行停止服務所需的關閉操作。 FileStream fs = new FileStream(@"C:\Windows\JinXBWinServer.log", FileMode.OpenOrCreate, FileAccess.Write); StreamWriter sw = new StreamWriter(fs); sw.BaseStream.Seek(0, SeekOrigin.End); sw.WriteLine("WindowsService: Service Stopped" + DateTime.Now.ToString() + "\n"); sw.Flush(); sw.Close(); fs.Close(); }
可以分別通過OnStart和OnStop去記錄一下服務操作記錄,來做個測試。
服務編寫完,先別急着F5測試。因為運行權限的問題,這時可能會出現1053:服務沒有及時響應啟動或控制請求。這是因為VS權限不足,可以在debug文件中用管理員運行測試一下,是不是OK了。
特別注意:每次更新安裝都要用最新的SetUp.exe安裝包,點擊右鍵生成可以自動在“SetUp\Express\SingleImage\DiskImages\DISK1\setup.exe”路徑下生成exe安裝文件,一定記得安裝最新版。
InstallShield Limited Edition for Visual Studio的具體使用,可以網上找一下,也可以參考這里:http://blog.csdn.net/kingmax54212008/article/details/44303539