一步一步用C#寫一個檢查SQL Server假死警報服務


本文主要是寫Windows 服務的一個實際應用。包括一個后台定時執行檢查的服務、寫文本日志功能、加密解密功能、發送郵件功能、一個XML的配置文件和讀取XML配置內容功能、服務的安裝和刪除功能。

我先說明,我不在這里研究SQL Server為什么有假死這樣的現象,實際在工作上就是碰到了多次這樣的情況,即服務運行,但不提供服務。

VS中不可以調試服務,所以有很多寫LOG的調用,是為了方便調試跟蹤。

為防止后續發生SQL Server服務假死(即服務運行,但不提供服務)的情況可以更及時的處理,一發動千均,一出問題,整個生產現場就得停工,所以才有本文。

 

資料和要求:

主要的MES數據庫有18個,內容包含以下Instance和Database:

UsedFor

Instance

Database

CPT

[HZXL1\HZXL1]

XLProd_Cree_HZ2

CPT

[HZXL1\HZXL1]

XLProd_Cree_HZ2_Archive

CPT

[HZXL1\HZXL1]

XLSite_Cree_HZ2

Camstar OLTP

[HZCS1\HZCS1]

FASSL

Camstar OLTP

[HZCS1\HZCS1]

InSiteDB

Camstar OLTP

[HZCS1\HZCS1]

InSiteDB_CSIPurgeDB

Camstar ODS

HZCSODS01

CNSSLRTS

Camstar ODS

HZCSODS01

InSiteODS

PNT

HZBACK01

CreeMES_PNT

PNT

HZBACK01

CreeMES_ReplStage

PNT

HZBACK01

CrystalReports2008

PNT

HZBACK01

FAOpto

PNT

HZBACK01

Intranet_Apps

PNT

HZBACK01

PNT_Parameters

PNT

HZBACK01

PNTLampInfo

PNT

HZBACK01

ProberInfo

PNT

HZBACK01

WaferWorks_PT

PNT

HZBACK01

WaferWorks_Sphere

當無法連接數據庫時,發出警報。

可以連入時,每個判斷語句只需抓取sys.sysindexes的第一筆記錄,sample如下:

select top 1 'OK' from sys.sysindexes with(nolock)

判斷所有數據庫均能抓出數據,如果有不能抓出的數據,發出警報並顯示出詳細信息.

警報地址---(#Asia_IT_Operations; #HZ_IS_Helpdesk)

這樣第一時間Helpdesk會收到信息,確認問題無法處理時,可以聯系二線人員處理。

 

實際的效果:

生產的服務程序文件列表,包括主程序,安裝和刪除批處理

clip_image001

 

安裝后在服務中可以看到服務的情況

clip_image002

 

單個檢查項對應產生的日志文件

clip_image001[6]

主程序日志文件

clip_image001[8]

 

報警郵件

clip_image001[10]

 

功能實現:

由於很多童孩都不多用服務,還是一步一步的寫出來,讓想試試又未試過的也可以照做。

我要檢查的數據庫眾多,18個,就18個嗎?

所以這些都要用配置文件來配置,可加可減才行.

日志是少不了的,那是否一定就要呢?什么時候都是有比無要好,但是可有可無才是靈活的方式,那要還是不要?

功能是要有,但是用與不用,改改參數就可以吧,那參數也放配置文件中好了。

要發郵件,SMTP是固定的嗎?有其它的沒有?可能想更換的時候也是有的?

也就是說SMTP的信息(服務器、用戶名、密碼等)都放配置文件。

還有收郵件的人員、日志文件的名稱和路徑、一些默認值、具體的數據庫信息都應該在配置文件中。

由於是給一線人員檢查用的,所以敏感信息需要加密后再放配置文件中,最后確定配置文件使用一個自定義的XML最好。

由上邊的內容,應該需要寫文本日志功能、一個XML的配置文件、加密解密功能、發送郵件功能、一個后台定時執行檢查的服務、讀取XML配置內容、服務的安裝和刪除功能.

OK,就一步一步來吧!

 

第一步:新建一個項目

如下圖,創建一個名為MonitorSqlServerWindowsService的Windows Service項目。

clip_image001

創建后的默認如下:

image

在屬性中更改名稱和服務名如下

image

 

第二步:加密解密功能實現

image

新建立一個類,名為MonitorSqlServerWindowsService

image

MonitorSqlServerWindowsService類的代碼:

   1:  using System;
   2:  using System.Security.Cryptography;
   3:  using System.IO;
   4:   
   5:  namespace Core.DarrenEncodeOrDecode
   6:  {
   7:      /// <summary>
   8:      /// 描述:EncodeOrDecode是加密解密類
   9:      /// 程序員:謝堂文(Darren Xie)
  10:      /// 創建日期:2012-01-18
  11:      /// 版本:1.0
  12:      /// </summary>
  13:      public class EncodeOrDecode
  14:      {
  15:          const string KEY_64 = "9Hgu#6w!";
  16:          const string IV_64 = "InitVect";
  17:          public EncodeOrDecode()
  18:          {
  19:              //
  20:              // TODO: Add constructor logic here
  21:              //
  22:          }
  23:          /// <summary>
  24:          /// 默認的加密方法,加密傳入的字符串,返回加密後的字符串
  25:          /// </summary>
  26:          /// <param name="data">需要加密的字符串</param>
  27:          /// <returns>加密後的字符串</returns>
  28:          public static string Encode(string data)
  29:          {
  30:              byte[] byKey = System.Text.ASCIIEncoding.ASCII.GetBytes(KEY_64);
  31:              byte[] byIV = System.Text.ASCIIEncoding.ASCII.GetBytes(IV_64);
  32:   
  33:              DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
  34:              int i = cryptoProvider.KeySize;
  35:              MemoryStream ms = new MemoryStream();
  36:              CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(byKey, byIV), CryptoStreamMode.Write);
  37:   
  38:              StreamWriter sw = new StreamWriter(cst);
  39:              sw.Write(data);
  40:              sw.Flush();
  41:              cst.FlushFinalBlock();
  42:              sw.Flush();
  43:              return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
  44:          }
  45:          /// <summary>
  46:          /// 自定義密鑰的加密方法,加密傳入的字符串,返回加密後的字符串
  47:          /// </summary>
  48:          /// <param name="data">需要加密的字符串</param>
  49:          /// <returns>加密後的字符串</returns>
  50:          public static string Encode(string data,string key,string iv)
  51:          {
  52:              byte[] byKey = System.Text.ASCIIEncoding.ASCII.GetBytes(key);
  53:              byte[] byIV = System.Text.ASCIIEncoding.ASCII.GetBytes(iv);
  54:   
  55:              DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
  56:              int i = cryptoProvider.KeySize;
  57:              MemoryStream ms = new MemoryStream();
  58:              CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(byKey, byIV), CryptoStreamMode.Write);
  59:   
  60:              StreamWriter sw = new StreamWriter(cst);
  61:              sw.Write(data);
  62:              sw.Flush();
  63:              cst.FlushFinalBlock();
  64:              sw.Flush();
  65:              return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
  66:          }
  67:   
  68:          /// <summary>
  69:          /// 默認的解密方法,傳入加密的字符串,返回解密後的字符串
  70:          /// </summary>
  71:          /// <param name="data">需要解密的字符串</param>
  72:          /// <returns>解密後的字符串</returns>
  73:          public static string Decode(string data)
  74:          {
  75:              byte[] byKey = System.Text.ASCIIEncoding.ASCII.GetBytes(KEY_64);
  76:              byte[] byIV = System.Text.ASCIIEncoding.ASCII.GetBytes(IV_64);
  77:   
  78:              byte[] byEnc;
  79:              try
  80:              {
  81:                  byEnc = Convert.FromBase64String(data);
  82:              }
  83:              catch
  84:              {
  85:                  return null;
  86:              }
  87:   
  88:              DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
  89:              MemoryStream ms = new MemoryStream(byEnc);
  90:              CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(byKey, byIV), CryptoStreamMode.Read);
  91:              StreamReader sr = new StreamReader(cst);
  92:              return sr.ReadToEnd();
  93:          }
  94:          /// <summary>
  95:          /// 自定義密鑰的解密方法,傳入加密的字符串,返回解密後的字符串
  96:          /// </summary>
  97:          /// <param name="data">需要解密的字符串</param>
  98:          /// <returns>解密後的字符串</returns>
  99:          public static string Decode(string data,string key,string iv)
 100:          {
 101:              byte[] byKey = System.Text.ASCIIEncoding.ASCII.GetBytes(key);
 102:              byte[] byIV = System.Text.ASCIIEncoding.ASCII.GetBytes(iv);
 103:   
 104:              byte[] byEnc;
 105:              try
 106:              {
 107:                  byEnc = Convert.FromBase64String(data);
 108:              }
 109:              catch
 110:              {
 111:                  return null;
 112:              }
 113:   
 114:              DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
 115:              MemoryStream ms = new MemoryStream(byEnc);
 116:              CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(byKey, byIV), CryptoStreamMode.Read);
 117:              StreamReader sr = new StreamReader(cst);
 118:              return sr.ReadToEnd();
 119:          }
 120:      }
 121:  }

 

第三步:建立XML配置文件

增加一個XML文件到項目中,名為ServerConfig.xml,代碼如下:

   1:  <?xml version="1.0" encoding="utf-8" ?>
   2:  <parameters>
   3:   
   4:    <!--標準基礎信息-->
   5:    <istest val="0">測試標識,1是測試,非1是正式</istest>
   6:    <checkTime val="120">檢查週期,單位是秒</checkTime>
   7:    <smtp name="你的SMTP服務器" from="你的郵箱地址" user="你的用戶名" pwd="M/R3ib7M0OVPpDWmAZjGGw==">郵件服務器信息</smtp>
   8:   
   9:    <defsqlUser dbuser="D+Zox91emVaNWnUtiLez9g==" userpwd="bCIkRm+dTA1kJO0oRlOLxg==">默認數據庫訪問賬號</defsqlUser>
  10:    <to email="#Asia_IT_Operations@XXXX.com; #HZ_IS_Helpdesk@XXXX.com;DarrenXie@XXXX.com"></to>
  11:    <isLog val="1">是否產生日誌文件,1產生,非1就不產生</isLog>
  12:    <LogFilePath val="">日誌文件存放路徑</LogFilePath>
  13:    <LogFileName val="">日誌文件名</LogFileName>
  14:    <sql val="select top 1 'OK' from sys.sysindexes with(nolock)"></sql>
  15:    <dbsrv srvname="HZXL1\HZXL1" dbname="XLProd_Cree_HZ2" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  16:    <dbsrv srvname="HZXL1\HZXL1" dbname="XLProd_Cree_HZ2_Archive" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  17:    <dbsrv srvname="HZXL1\HZXL1" dbname="XLSite_Cree_HZ2" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  18:    <dbsrv srvname="HZCS1\HZCS1" dbname="FASSL" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  19:    <dbsrv srvname="HZCS1\HZCS1" dbname="InSiteDB" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  20:    <dbsrv srvname="HZCS1\HZCS1" dbname="InSiteDB_CSIPurgeDB" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  21:    <dbsrv srvname="HZCSODS01" dbname="CNSSLRTS" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  22:    <dbsrv srvname="HZCSODS01" dbname="InSiteODS" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  23:    <dbsrv srvname="HZBACK01" dbname="CreeMES_PNT" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  24:    <dbsrv srvname="HZBACK01" dbname="CreeMES_ReplStage" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  25:    <dbsrv srvname="HZBACK01" dbname="CrystalReports2008" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  26:    <dbsrv srvname="HZBACK01" dbname="FAOpto" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  27:    <dbsrv srvname="HZBACK01" dbname="Intranet_Apps" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  28:    <dbsrv srvname="HZBACK01" dbname="PNT_Parameters" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  29:    <dbsrv srvname="HZBACK01" dbname="PNTLampInfo" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  30:    <dbsrv srvname="HZBACK01" dbname="ProberInfo" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  31:    <dbsrv srvname="HZBACK01" dbname="WaferWorks_PT" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  32:    <dbsrv srvname="HZBACK01" dbname="WaferWorks_Sphere" dbuser="" userpwd="" sql="" descr="" LogFileName="">數據庫信息</dbsrv>
  33:  </parameters>

 

第四步:寫文本日志功能

增加一個類,名為FileLog.cs

代碼如下:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.IO;//StreamWriter
   6:  using System.Collections;//arraylist
   7:   
   8:  namespace Core.DarrenCoreLib.Log
   9:  {
  10:      /// <summary>
  11:      /// 描述:寫TXT格式的LOG
  12:      /// 程序員:謝堂文(Darren Xie)
  13:      /// 創建日期:2012-02-09
  14:      /// 版本:1.0
  15:      /// </summary>
  16:      public static class FileLog
  17:      {
  18:          public static void writeTotxt(string fullFilepath, string ppContent)
  19:          {
  20:              StreamWriter Sw1 = null;
  21:              try
  22:              {
  23:                  Sw1 = new StreamWriter(fullFilepath, true, System.Text.Encoding.UTF8);
  24:                  {
  25:                      Sw1.WriteLine(ppContent);
  26:                  }
  27:              }
  28:              catch (Exception ef)
  29:              {
  30:                  throw new Exception(ef.Message);
  31:              }
  32:              finally
  33:              {
  34:                  try
  35:                  {
  36:                      Sw1.Close();
  37:                  }
  38:                  catch
  39:                  {
  40:                  }
  41:              }
  42:   
  43:          }
  44:      }
  45:  }
  46:   

第五步:增加一個類用於實際的數據庫檢查對象,並且保存配置文件中對應的屬性以及寫日志、執行檢查、發送郵件等,具體看代碼注釋會更明白,就名為Srv.cs

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.Net.Mail;
   6:  using System.Data.SqlClient;
   7:  using System.Data;
   8:  using System.Net;
   9:   
  10:  namespace MonitorSqlServerWindowsService
  11:  {
  12:      /// <summary>
  13:      /// 描述:
  14:      /// 程序員:謝堂文(Darren Xie)
  15:      /// 創建日期:
  16:      /// 版本:1.0
  17:      /// </summary>
  18:      public class Srv
  19:      {
  20:          
  21:          string smtpName;
  22:          string smtpPwd;
  23:          string smtpUser;
  24:          string from;
  25:          string[] to;
  26:          string srvname;
  27:          string dbname;
  28:          string dbuser;
  29:          string userpwd;
  30:          string sql;
  31:          string descr;
  32:          int isLog;
  33:          string logFilePath;
  34:          string logFileName;
  35:   
  36:          /// <summary>
  37:          /// 生產日誌文件名稱
  38:          /// </summary>
  39:          public string LogFileName
  40:          {
  41:              get { return logFileName; }
  42:              set { logFileName = value; }
  43:          }
  44:          /// <summary>
  45:          /// 日誌文件存放的路徑
  46:          /// </summary>
  47:          public string LogFilePath
  48:          {
  49:              get { return logFilePath; }
  50:              set { logFilePath = value; }
  51:          }
  52:          /// <summary>
  53:          /// 是否產生日誌文件
  54:          /// </summary>
  55:          public int IsLog
  56:          {
  57:              get { return isLog; }
  58:              set { isLog = value; }
  59:          }
  60:   
  61:          /// <summary>
  62:          /// SMTP服務器
  63:          /// </summary>
  64:          public string SmtpName
  65:          {
  66:              get { return smtpName; }
  67:              set { smtpName = value; }
  68:          }
  69:         
  70:          /// <summary>
  71:          /// 用於發郵件的SMTP用戶密碼
  72:          /// </summary>
  73:          public string SmtpPwd
  74:          {
  75:              get { return smtpPwd; }
  76:              set { smtpPwd = value; }
  77:          }
  78:          
  79:          /// <summary>
  80:          /// 用於發郵件的SMTP用戶名
  81:          /// </summary>
  82:          public string SmtpUser
  83:          {
  84:              get { return smtpUser; }
  85:              set { smtpUser = value; }
  86:          }
  87:          
  88:          /// <summary>
  89:          /// 用於發郵件的SMTP用戶名郵件地址
  90:          /// </summary>
  91:          public string From
  92:          {
  93:              get { return from; }
  94:              set { from = value; }
  95:          }
  96:          
  97:         /// <summary>
  98:         /// 收件人地址
  99:         /// </summary>
 100:          public string[] To
 101:          {
 102:              get { return to; }
 103:              set { to = value; }
 104:          }
 105:          /// <summary>
 106:          /// 連接字符串
 107:          /// </summary>
 108:          public string ConnectionString
 109:          {
 110:              get
 111:              {
 112:                  return @"server="+Srvname+";database="+Dbname+";uid="+Core.DarrenEncodeOrDecode.EncodeOrDecode.Decode( Dbuser)+";pwd="+Core.DarrenEncodeOrDecode.EncodeOrDecode.Decode(Userpwd)+"";
 113:              }
 114:          }
 115:          
 116:   
 117:          public string Srvname
 118:          {
 119:              get { return srvname; }
 120:              set { srvname = value; }
 121:          }
 122:          
 123:          /// <summary>
 124:          /// 數據庫所在的服務器名
 125:          /// </summary>
 126:          public string Dbname
 127:          {
 128:              get { return dbname; }
 129:              set { dbname = value; }
 130:          }
 131:          
 132:          /// <summary>
 133:          /// 數據庫用戶名
 134:          /// </summary>
 135:          public string Dbuser
 136:          {
 137:              get { return dbuser; }
 138:              set { dbuser = value; }
 139:          }
 140:          
 141:          /// <summary>
 142:          /// 數據庫用戶的密碼
 143:          /// </summary>
 144:          public string Userpwd
 145:          {
 146:              get { return userpwd; }
 147:              set { userpwd = value; }
 148:          }
 149:          
 150:          /// <summary>
 151:          /// 檢查用的SQL語句
 152:          /// </summary>
 153:          public string Sql
 154:          {
 155:              get { return sql; }
 156:              set { sql = value; }
 157:          }
 158:          
 159:          /// <summary>
 160:          /// 描述信息
 161:          /// </summary>
 162:          public string Descr
 163:          {
 164:              get { return descr; }
 165:              set { descr = value; }
 166:          }
 167:          /// <summary>
 168:          /// 執行連接和查詢測試
 169:          /// </summary>
 170:          public void Chk()
 171:          {
 172:              using (SqlConnection conn = new SqlConnection(ConnectionString))
 173:              {
 174:                  try
 175:                  {
 176:                      writestr("開始連接" + Srvname + "服務器上的數據庫" + Dbname);
 177:                      conn.Open();
 178:                      writestr("連接" + Srvname + "服務器上的數據庫" + Dbname + "成功");
 179:   
 180:                      writestr("開始測試查詢" + Srvname + "服務器上的數據庫" + Dbname + "上的數據");
 181:   
 182:                      if (Core.DarrenCoreLib.DB.SqlHelper.ExecuteScalar(conn, CommandType.Text, Sql).ToString().ToUpper() == "OK")
 183:                      {
 184:                          writestr("查詢" + Srvname + "服務器上的數據庫" + Dbname + "數據測試成功");
 185:                      }
 186:                      else
 187:                      {
 188:                          throw new Exception("查詢" + Srvname + "服務器上的數據庫" + Dbname + "數據測試失敗");
 189:                      }
 190:                  }
 191:                  catch (Exception ee)
 192:                  {
 193:                      
 194:                          writestr(Srvname + "服務器上的數據庫" + Dbname + "檢查失敗" + ee.Message);
 195:                          writestr("準備發送郵件");
 196:                          writestr(this.To[0]);
 197:                          string errMsg = ee.Message;
 198:                      try
 199:                      {
 200:                          if (this.From.Trim() == string.Empty)
 201:                          {
 202:                              throw new Exception("沒有指定發件者地址。");
 203:                          }
 204:                          if (this.Srvname.Trim() == string.Empty)
 205:                          {
 206:                              throw new Exception("沒有指定服務器。");
 207:                          }
 208:                          if (this.Dbname.Trim() == string.Empty)
 209:                          {
 210:                              throw new Exception("沒有指定數據庫。");
 211:                          }
 212:                          if (this.To.Length == 0)
 213:                          {
 214:                              throw new Exception("沒有指定收件者地址。");
 215:                          }
 216:   
 217:                          if (this.SendMail(this.From, this.To, "檢查服務器 " + this.Srvname + "上的數據庫 " + this.Dbname + " 失敗", "<H1>SQL Server假死警報服務! </H1><br/>   <b>信息內容:<b/>" + errMsg + "<br/>服務器:" + this.Srvname + "<br/>數據庫:" + this.Dbname +"<br/>來自配置文件的數據庫描述信息:"+this.Descr.ToString()+ "<br/>請注意檢查確認,這是郵系統自動檢查發出的信息。<br/>來自服務器:" + Dns.GetHostName()))
 218:                          {
 219:                              writestr("發送郵件成功");
 220:                          }
 221:                      }
 222:                      catch (Exception em)
 223:                      {
 224:                          writestr("發送郵件失敗,"+em.Message);
 225:                      }
 226:                  }
 227:                  finally
 228:                  {
 229:                      try
 230:                      {
 231:                          conn.Close();
 232:                      }
 233:                      catch { }
 234:                  }
 235:              }
 236:          }
 237:          /// <summary>
 238:          /// 寫日誌文件
 239:          /// </summary>
 240:          /// <param name="readme"></param>
 241:          private void writestr(string readme)
 242:          {
 243:              if (IsLog == 1)
 244:              {
 245:                  Core.DarrenCoreLib.Log.FileLog.writeTotxt((LogFilePath + LogFileName), "\r\n事件:" + readme + "\r\n操作時間:" + System.DateTime.Now.ToString("yyy-MM-dd HH:mm:ss"));
 246:              }
 247:          }
 248:          /// <summary>
 249:          /// 發送郵件 
 250:          /// </summary>
 251:          /// <param name="messagefrom"></param>
 252:          /// <param name="MessageTo"></param>
 253:          /// <param name="MessageSubject"></param>
 254:          /// <param name="MessageBody"></param>
 255:          /// <returns></returns>
 256:          public bool SendMail(string messagefrom, string[] MessageTo, string MessageSubject, string MessageBody)
 257:          {
 258:              MailMessage message = new MailMessage();
 259:              message.SubjectEncoding = System.Text.Encoding.Unicode;
 260:              SmtpClient sc = new SmtpClient();
 261:              try
 262:              {
 263:                  MailAddress Messagefrom = new MailAddress(messagefrom);
 264:                  message.From = Messagefrom;
 265:                 
 266:                  foreach (string to in MessageTo)
 267:                  {
 268:                      writestr(to);
 269:                      message.To.Add(to);
 270:                  }//收件人郵箱地址可以是多個以實現群發
 271:                  if (MessageSubject.Trim() == string.Empty)
 272:                  {
 273:                      throw new Exception("沒有指定郵件標題。");
 274:                  }
 275:                  message.Subject = MessageSubject; 
 276:                  if (messagefrom.Trim() == string.Empty)
 277:                  {
 278:                      throw new Exception("沒有指定郵件內容。");
 279:                  }
 280:                  message.Body = MessageBody;
 281:                  message.IsBodyHtml = true;              //是否為html格式
 282:                  message.Priority = MailPriority.High;  //發送郵件的優先等級  
 283:                  if (SmtpName.Trim() == string.Empty)
 284:                  {
 285:                      throw new Exception("沒有指定SMTP地址。");
 286:                  }
 287:                  if (SmtpUser.Trim() == string.Empty)
 288:                  {
 289:                      throw new Exception("沒有指定SMTP用戶名。");
 290:                  }
 291:                  if (SmtpPwd.Trim() == string.Empty)
 292:                  {
 293:                      throw new Exception("沒有指定SMTP密碼。");
 294:                  }
 295:                  sc.Host = SmtpName;              //指定發送郵件的服務器地址或IP
 296:                  //sc.Port = 212;                          //指定發送郵件端口
 297:                  //   sc.UseDefaultCredentials = true;
 298:                  // sc.EnableSsl = true;
 299:                  sc.Credentials = new System.Net.NetworkCredential(SmtpUser, Core.DarrenEncodeOrDecode.EncodeOrDecode.Decode(SmtpPwd)); //指定登錄服務器的用戶名和密碼
 300:              }
 301:              catch (Exception ee)
 302:              {
 303:                  throw new Exception(ee.Message);       
 304:              }
 305:              
 306:              try
 307:              {
 308:                  sc.Send(message);      //發送郵件
 309:              }
 310:              catch (Exception e)
 311:              {
 312:                  throw new Exception(e.Message);                
 313:              }
 314:              return true;
 315:          }
 316:      }
 317:  }

第六步:在服務的設計視圖中,增加一個timer控件名為timerChkSql,有一點要注意,timer有不同的,,要加正確的命名空間下的timer控件,請注意清楚如下的區另,紅色標記的才是正確的,否則到時會不工作;

在控件的選擇項中可以看到它們

image

之后你會看到

image

 

第七步:回到服務的功能上,需要組裝上邊幾個功能在一起,對了,先要讀取配置文件,讀取時建立每個數據庫對象

先建立一個List來放對象,在MyService.cs中增加以下屬性

private System.Collections.Generic.List<Srv> srvList = new List<Srv>();
        /// <summary>
        /// 用城保存需要檢查的數據庫的信息對象列表
        /// </summary>
        public System.Collections.Generic.List<Srv> SrvList
        {
            get { return srvList; }
            set { srvList = value; }
        }

OnStart中讀取配置文件時,用string filexml = System.Windows.Forms.Application.StartupPath.ToString() + @"\ServerConfig.xml"來取配置文件的實際路徑,這樣可以取到安裝的目錄。

在timerChkSql_Elapsed中增加定時檢查的功能代碼

//執行檢查
           writestr("執行檢查。");
           try
           {               
               foreach (Srv s in SrvList)
               {
                   writestr("執行檢查" + s.Dbname);
                   s.Chk();
               }
           }
           catch (Exception ee)
           {
               writestr("執行檢查出錯。" + ee.Message);
               EventLog.WriteEntry("執行檢查出錯。" + ee.Message);
           }

 

完整的MyService.cs代碼:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel;
   4:  using System.Data;
   5:  using System.Diagnostics;
   6:  using System.Linq;
   7:  using System.ServiceProcess;
   8:  using System;
   9:  using System.Collections.Generic;
  10:  using System.ComponentModel;
  11:  using System.Data;
  12:  using System.Diagnostics;
  13:  using System.ServiceProcess;
  14:  using System.IO;
  15:  using System.Text;
  16:  using System.Timers;
  17:  using System.Threading;
  18:  using Core.DarrenCoreLib;
  19:  using System.Net.Mail;
  20:  using System.Data.SqlClient;
  21:  using System.Xml;
  22:   
  23:  //=================================================================================  
  24:  //  
  25:  //        Copyright (C) 2012, 謝堂文(Darren Xie)     
  26:  //        All rights reserved  
  27:  //        Created by Darren at 12-03-15 14:12:57   
  28:  //        Email: 13923613791@139.com  
  29:  //        http://www.cnblogs.com/yiyumeng/  
  30:  //  
  31:  //================================================================================== 
  32:   
  33:  namespace MonitorSqlServerWindowsService
  34:  {
  35:      public partial class MyService : ServiceBase
  36:      {
  37:          
  38:          private System.Collections.Generic.List<Srv> srvList = new List<Srv>();
  39:          /// <summary>
  40:          /// 用城保存需要檢查的數據庫的信息對象列表
  41:          /// </summary>
  42:          public System.Collections.Generic.List<Srv> SrvList
  43:          {
  44:              get { return srvList; }
  45:              set { srvList = value; }
  46:          }
  47:          public MyService()
  48:          {
  49:              InitializeComponent();
  50:          }
  51:   
  52:          protected override void OnStart(string[] args)
  53:          {
  54:   
  55:              int istest = 0;
  56:              string defsqlUser_dbuser = string.Empty;
  57:              string defsqlUser_userpwd = string.Empty;
  58:              string smtpName = string.Empty;
  59:              string smtpFrom = string.Empty;
  60:              string smtpUser = string.Empty;
  61:              string smtpPwd = string.Empty;
  62:              string[] to = null;
  63:              int isLog = 0;
  64:              string LogFilePath = string.Empty;
  65:              string LogFileName = string.Empty;
  66:              string sql = string.Empty;
  67:   
  68:              EventLog.WriteEntry("檢查SQL服務器的服務啟動。");//在系統事件查看器里的應用程序事件里來源的描述     
  69:              writestr("服務啟動");//自定義文本日志   
  70:              XmlDocument xmlDoc = new XmlDocument();
  71:              try
  72:              {
  73:                  string filexml = System.Windows.Forms.Application.StartupPath.ToString() + @"\ServerConfig.xml";
  74:                  if (!System.IO.File.Exists(filexml))
  75:                  {
  76:                      throw new Exception("找不到配置文件" + filexml);
  77:                  }
  78:                  writestr("讀取檢查週期時間");
  79:                  xmlDoc.Load(filexml);
  80:              }
  81:              catch (Exception ee)
  82:              {
  83:                  EventLog.WriteEntry("檢查SQL服務器的服務啟動時讀取檢查週期時間出錯。" + ee.Message);
  84:                  writestr("檢查SQL服務器的服務啟動時讀取檢查週期時間出錯。" + ee.Message);
  85:              }
  86:              XmlNodeList nodeList = xmlDoc.SelectSingleNode("parameters").ChildNodes;
  87:              try
  88:              {
  89:                  writestr("開始讀取配置內容");
  90:                  foreach (XmlNode xn in nodeList)
  91:                  {
  92:   
  93:                      if (xn.Name == "checkTime")
  94:                      {
  95:                          timerChkSql.Interval = (double.Parse(xn.Attributes["val"].Value))*1000;
  96:                          writestr("讀取到檢查週期時間" + xn.Attributes["val"].Value);
  97:                      }
  98:                      if (xn.Name == "istest")
  99:                      {
 100:                          istest = int.Parse(xn.Attributes["val"].Value);
 101:   
 102:                      }
 103:                      if (xn.Name == "smtp")
 104:                      {
 105:                          smtpName = xn.Attributes["name"].Value;
 106:   
 107:                          smtpFrom = xn.Attributes["from"].Value;
 108:   
 109:                          smtpUser = xn.Attributes["user"].Value;
 110:   
 111:                          smtpPwd = xn.Attributes["pwd"].Value;
 112:   
 113:   
 114:                      }
 115:                      if (xn.Name == "defsqlUser")
 116:                      {
 117:   
 118:                          defsqlUser_dbuser = xn.Attributes["dbuser"].Value;
 119:   
 120:                          defsqlUser_userpwd = xn.Attributes["userpwd"].Value;
 121:   
 122:                      }
 123:                      if (xn.Name == "to")
 124:                      {
 125:                          to = xn.Attributes["email"].Value.Split(new char[] { ';' });
 126:   
 127:                      }
 128:                      if (xn.Name == "isLog")
 129:                      {
 130:                          isLog = int.Parse(xn.Attributes["val"].Value);
 131:   
 132:                      }
 133:                      if (xn.Name == "LogFilePath")
 134:                      {
 135:                          LogFilePath = xn.Attributes["val"].Value == "" ? System.Windows.Forms.Application.StartupPath.ToString() +@"\": xn.Attributes["val"].Value;
 136:   
 137:                      }
 138:                      if (xn.Name == "sql")
 139:                      {
 140:                          sql = xn.Attributes["val"].Value;
 141:   
 142:                      }
 143:                      if (xn.Name == "LogFileName")
 144:                      {
 145:   
 146:                          LogFileName = xn.Attributes["val"].Value;
 147:   
 148:                      }
 149:                      if (xn.Name == "dbsrv")
 150:                      {
 151:                          Srv s = new Srv();
 152:                          s.IsLog = isLog;
 153:                          s.Srvname = xn.Attributes["srvname"].Value;
 154:                          s.Dbname = xn.Attributes["dbname"].Value;
 155:                          s.Dbuser = xn.Attributes["dbuser"].Value != "" ? xn.Attributes["dbuser"].Value : defsqlUser_dbuser;
 156:                          s.Userpwd = xn.Attributes["userpwd"].Value != "" ? xn.Attributes["userpwd"].Value : defsqlUser_userpwd;
 157:                          s.Sql = xn.Attributes["sql"].Value != "" ? xn.Attributes["sql"].Value : sql;
 158:                          s.Descr = xn.Attributes["descr"].Value;
 159:                          s.LogFileName = xn.Attributes["LogFileName"].Value != "" ? xn.Attributes["LogFileName"].Value : (LogFileName != "" ? LogFileName : s.Dbname + "ChkLog.txt");
 160:                          s.LogFilePath = LogFilePath;
 161:                          s.To = to;
 162:                          s.From = smtpFrom;
 163:                          s.SmtpName = smtpName;
 164:                          s.SmtpPwd = smtpPwd;
 165:                          s.SmtpUser = smtpUser;           
 166:                          SrvList.Add(s);
 167:   
 168:                      }
 169:   
 170:   
 171:                  }
 172:                  writestr("讀取配置內容完成。");
 173:   
 174:              }
 175:              catch (Exception ee)
 176:              {
 177:                  EventLog.WriteEntry("檢查SQL服務器的服務啟動時讀取配置內容出錯。" + ee.Message);
 178:                  writestr("檢查SQL服務器的服務啟動時讀取配置內容出錯。" + ee.Message);
 179:              }
 180:   
 181:          }
 182:   
 183:          protected override void OnStop()
 184:          {
 185:              writestr("服務停止");
 186:              EventLog.WriteEntry("檢查SQL服務器的服務停止。");
 187:          }
 188:   
 189:          private void timerChkSql_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
 190:          {
 191:              //執行檢查
 192:              writestr("執行檢查。");
 193:              try
 194:              {                
 195:                  foreach (Srv s in SrvList)
 196:                  {
 197:                      writestr("執行檢查" + s.Dbname);
 198:                      s.Chk();
 199:                  }
 200:              }
 201:              catch (Exception ee)
 202:              {
 203:                  writestr("執行檢查出錯。" + ee.Message);
 204:                  EventLog.WriteEntry("執行檢查出錯。" + ee.Message);
 205:              }
 206:   
 207:   
 208:   
 209:   
 210:          }
 211:          public void writestr(string readme)
 212:          {
 213:              Core.DarrenCoreLib.Log.FileLog.writeTotxt((System.Windows.Forms.Application.StartupPath.ToString() + @"\" + "MonitorSqlServerWindowsService.txt"), "\r\n事件:" + readme + "\r\n操作時間:" + System.DateTime.Now.ToString("yyy-MM-dd HH:mm:ss"));
 214:          }
 215:   
 216:   
 217:   
 218:      }
 219:  }

 

第八步:增加安裝

在設計頁面點右鍵增加安裝,之后你會看到以下的樣子,並分別進行設定。

注意設定你的顯示信息和服務名稱,不是控件名。

同時也要設定StartType,我設為自動,這樣一開機就會自動啟用。

image

 

注意使用LocalSystem賬號的設定,否則無法自動運行。

image

 

第九步:生成

先取Releasc的方式進行Build.

image

你會看到在BIN目錄下有一個Release。

就會有以下圖文件,除標了顏色的四個

image

 

從C:\Windows\Microsoft.NET\Framework\v2.0.50727中復制InstallUtil.exe和InstallUtilLib.dll這兩個文件出來。

從源代碼文件中復制配置文件ServerConfig.xml出來。

建立安裝批處理文件Install.bat,假設安裝目錄是C:\MonitorSqlServerWindowsService:

c:
cd C:\MonitorSqlServerWindowsService
InstallUtil MonitorSqlServerWindowsService.exe
net start MonitorSqlServerStatus

 

建立反安裝批處理文件UnInstall.bat,假設安裝目錄是C:\MonitorSqlServerWindowsService:

c:
cd C:\MonitorSqlServerWindowsService
net stop MonitorSqlServerStatus
InstallUtil -u MonitorSqlServerWindowsService.exe

之后把所有這個文件夾下的文件復制到一個MonitorSqlServerWindowsService文件夾下。要在那台電腦站安裝,說復制到C盤再運行安裝批處理就可以了。

 

另外,我把發郵件的地址加入139郵箱,並設好139郵件用長信息通知,那就可以在收到郵件時,也收到信息,在信息內容中就可以有350個字的內容,看你的提醒內容吧。

 

文墨所限,請多多指教。

請尊重原創版權,轉載注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM