设为首页 收藏本站
查看: 3823|回复: 0

[经验分享] 一步一步用C#写一个检查SQL Server假死警报服务

[复制链接]

尚未签到

发表于 2015-6-28 10:44:48 | 显示全部楼层 |阅读模式
  本文主要是写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会收到信息,确认问题无法处理时,可以联系二线人员处理。
  
  实际的效果:
  生产的服务程序文件列表,包括主程序,安装和删除批处理
DSC0000.jpg
  
  安装后在服务中可以看到服务的情况
DSC0001.jpg
  
  单个检查项对应产生的日志文件
DSC0002.jpg
  主程序日志文件
DSC0003.jpg
  
  报警邮件
DSC0004.jpg
  
  功能实现:
  由于很多童孩都不多用服务,还是一步一步的写出来,让想试试又未试过的也可以照做。

  我要检查的数据库众多,18个,就18个吗?
  所以这些都要用配置文件来配置,可加可减才行.


  日志是少不了的,那是否一定就要呢?什么时候都是有比无要好,但是可有可无才是灵活的方式,那要还是不要?
  功能是要有,但是用与不用,改改参数就可以吧,那参数也放配置文件中好了。


  要发邮件,SMTP是固定的吗?有其它的没有?可能想更换的时候也是有的?
  也就是说SMTP的信息(服务器、用户名、密码等)都放配置文件。


  还有收邮件的人员、日志文件的名称和路径、一些默认值、具体的数据库信息都应该在配置文件中。


  由于是给一线人员检查用的,所以敏感信息需要加密后再放配置文件中,最后确定配置文件使用一个自定义的XML最好。

  由上边的内容,应该需要写文本日志功能、一个XML的配置文件、加密解密功能、发送邮件功能、一个后台定时执行检查的服务、读取XML配置内容、服务的安装和删除功能.
  OK,就一步一步来吧!
  
  第一步:新建一个项目
  如下图,创建一个名为MonitorSqlServerWindowsService的Windows Service项目。
DSC0005.png
  创建后的默认如下:
DSC0006.png
  在属性中更改名称和服务名如下
DSC0007.png
  
  第二步:加密解密功能实现
DSC0008.png
  新建立一个类,名为MonitorSqlServerWindowsService
DSC0009.png
  MonitorSqlServerWindowsService类的代码:



   1:  using System;
   2:  using System.Security.Cryptography;
   3:  using System.IO;
   4:   
   5:  namespace Core.DarrenEncodeOrDecode
   6:  {
   7:      ///
   8:      /// 描述:EncodeOrDecode是加密解密類
   9:      /// 程序員:谢堂文(Darren Xie)
  10:      /// 創建日期:2012-01-18
  11:      /// 版本:1.0
  12:      ///
  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:          ///
  24:          /// 默認的加密方法,加密傳入的字符串,返回加密後的字符串
  25:          ///
  26:          /// 需要加密的字符串
  27:          /// 加密後的字符串
  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:          ///
  46:          /// 自定義密鑰的加密方法,加密傳入的字符串,返回加密後的字符串
  47:          ///
  48:          /// 需要加密的字符串
  49:          /// 加密後的字符串
  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:          ///
  69:          /// 默認的解密方法,傳入加密的字符串,返回解密後的字符串
  70:          ///
  71:          /// 需要解密的字符串
  72:          /// 解密後的字符串
  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:          ///
  95:          /// 自定義密鑰的解密方法,傳入加密的字符串,返回解密後的字符串
  96:          ///
  97:          /// 需要解密的字符串
  98:          /// 解密後的字符串
  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:  
   2:  
   3:   
   4:   
   5:    測試標識,1是測試,非1是正式
   6:    檢查週期,單位是秒
   7:    郵件服務器信息
   8:   
   9:    默認數據庫訪問賬號
  10:   
  11:    是否產生日誌文件,1產生,非1就不產生
  12:    日誌文件存放路徑
  13:    日誌文件名
  14:   
  15:    數據庫信息
  16:    數據庫信息
  17:    數據庫信息
  18:    數據庫信息
  19:    數據庫信息
  20:    數據庫信息
  21:    數據庫信息
  22:    數據庫信息
  23:    數據庫信息
  24:    數據庫信息
  25:    數據庫信息
  26:    數據庫信息
  27:    數據庫信息
  28:    數據庫信息
  29:    數據庫信息
  30:    數據庫信息
  31:    數據庫信息
  32:    數據庫信息
  33:  
  
  第四步:写文本日志功能
  增加一个类,名为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:      ///
  11:      /// 描述:寫TXT格式的LOG
  12:      /// 程序員:谢堂文(Darren Xie)
  13:      /// 創建日期:2012-02-09
  14:      /// 版本:1.0
  15:      ///
  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:      ///
  13:      /// 描述:
  14:      /// 程序員:谢堂文(Darren Xie)
  15:      /// 創建日期:
  16:      /// 版本:1.0
  17:      ///
  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:          ///
  37:          /// 生產日誌文件名稱
  38:          ///
  39:          public string LogFileName
  40:          {
  41:              get { return logFileName; }
  42:              set { logFileName = value; }
  43:          }
  44:          ///
  45:          /// 日誌文件存放的路徑
  46:          ///
  47:          public string LogFilePath
  48:          {
  49:              get { return logFilePath; }
  50:              set { logFilePath = value; }
  51:          }
  52:          ///
  53:          /// 是否產生日誌文件
  54:          ///
  55:          public int IsLog
  56:          {
  57:              get { return isLog; }
  58:              set { isLog = value; }
  59:          }
  60:   
  61:          ///
  62:          /// SMTP服務器
  63:          ///
  64:          public string SmtpName
  65:          {
  66:              get { return smtpName; }
  67:              set { smtpName = value; }
  68:          }
  69:         
  70:          ///
  71:          /// 用於發郵件的SMTP用戶密碼
  72:          ///
  73:          public string SmtpPwd
  74:          {
  75:              get { return smtpPwd; }
  76:              set { smtpPwd = value; }
  77:          }
  78:         
  79:          ///
  80:          /// 用於發郵件的SMTP用戶名
  81:          ///
  82:          public string SmtpUser
  83:          {
  84:              get { return smtpUser; }
  85:              set { smtpUser = value; }
  86:          }
  87:         
  88:          ///
  89:          /// 用於發郵件的SMTP用戶名郵件地址
  90:          ///
  91:          public string From
  92:          {
  93:              get { return from; }
  94:              set { from = value; }
  95:          }
  96:         
  97:         ///
  98:         /// 收件人地址
  99:         ///
100:          public string[] To
101:          {
102:              get { return to; }
103:              set { to = value; }
104:          }
105:          ///
106:          /// 連接字符串
107:          ///
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:          ///
124:          /// 數據庫所在的服務器名
125:          ///
126:          public string Dbname
127:          {
128:              get { return dbname; }
129:              set { dbname = value; }
130:          }
131:         
132:          ///
133:          /// 數據庫用戶名
134:          ///
135:          public string Dbuser
136:          {
137:              get { return dbuser; }
138:              set { dbuser = value; }
139:          }
140:         
141:          ///
142:          /// 數據庫用戶的密碼
143:          ///
144:          public string Userpwd
145:          {
146:              get { return userpwd; }
147:              set { userpwd = value; }
148:          }
149:         
150:          ///
151:          /// 檢查用的SQL語句
152:          ///
153:          public string Sql
154:          {
155:              get { return sql; }
156:              set { sql = value; }
157:          }
158:         
159:          ///
160:          /// 描述信息
161:          ///
162:          public string Descr
163:          {
164:              get { return descr; }
165:              set { descr = value; }
166:          }
167:          ///
168:          /// 執行連接和查詢測試
169:          ///
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 + " 失敗", "SQL Server假死警报服務!    信息內容:" + errMsg + "服務器:" + this.Srvname + "數據庫:" + this.Dbname +"來自配置文件的數據庫描述信息:"+this.Descr.ToString()+ "請注意檢查確認,這是郵系統自動檢查發出的信息。來自服務器:" + 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:          ///
238:          /// 寫日誌文件
239:          ///
240:          ///
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:          ///
249:          /// 發送郵件
250:          ///
251:          ///
252:          ///
253:          ///
254:          ///
255:          ///
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控件,请注意清楚如下的区另,红色标记的才是正确的,否则到时会不工作;
  在控件的选择项中可以看到它们
DSC00010.png
  之后你会看到
DSC00011.png
  
  第七步:回到服务的功能上,需要组装上边几个功能在一起,对了,先要读取配置文件,读取时建立每个数据库对象
  先建立一个List来放对象,在MyService.cs中增加以下属性

  private System.Collections.Generic.List srvList = new List();
        ///  
        /// 用城保存需要檢查的數據庫的信息對象列表
        ///  
        public System.Collections.Generic.List 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.iyunv.com/yiyumeng/  
  30:  //  
  31:  //==================================================================================
  32:   
  33:  namespace MonitorSqlServerWindowsService
  34:  {
  35:      public partial class MyService : ServiceBase
  36:      {
  37:         
  38:          private System.Collections.Generic.List srvList = new List();
  39:          ///
  40:          /// 用城保存需要檢查的數據庫的信息對象列表
  41:          ///
  42:          public System.Collections.Generic.List 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,我设为自动,这样一开机就会自动启用。
DSC00012.png
  
  注意使用LocalSystem账号的设定,否则无法自动运行。
DSC00013.png
  
  第九步:生成
  先取Releasc的方式进行Build.
DSC00014.png
  你会看到在BIN目录下有一个Release。
  就会有以下图文件,除标了颜色的四个
DSC00015.png
  
  从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个字的内容,看你的提醒内容吧。
  
  文墨所限,请多多指教。
  请尊重原创版权,转载注明出处。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-81138-1-1.html 上篇帖子: Sql Server 锁 下篇帖子: SQL Server 性能优化之——系统化方法提高性能
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表